diff --git a/web/components/chat/ChatTextField/ChatTextField.tsx b/web/components/chat/ChatTextField/ChatTextField.tsx index f117700311..ae24eb5745 100644 --- a/web/components/chat/ChatTextField/ChatTextField.tsx +++ b/web/components/chat/ChatTextField/ChatTextField.tsx @@ -4,12 +4,16 @@ import React, { FC, useMemo, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { Transforms, createEditor, BaseEditor, Text, Descendant, Editor, Node, Path } from 'slate'; import { Slate, Editable, withReact, ReactEditor, useSelected, useFocused } from 'slate-react'; -import { EmojiPicker } from './EmojiPicker'; +import dynamic from 'next/dynamic'; import WebsocketService from '../../../services/websocket-service'; import { websocketServiceAtom } from '../../stores/ClientConfigStore'; import { MessageType } from '../../../interfaces/socket-events'; import styles from './ChatTextField.module.scss'; +// Lazy loaded components + +const EmojiPicker = dynamic(() => import('./EmojiPicker').then(mod => mod.EmojiPicker)); + type CustomElement = { type: 'paragraph' | 'span'; children: CustomText[] } | ImageNode; type CustomText = { text: string }; diff --git a/web/components/chat/ChatUserMessage/ChatUserMessage.tsx b/web/components/chat/ChatUserMessage/ChatUserMessage.tsx index c5bab3b745..ad0001c62c 100644 --- a/web/components/chat/ChatUserMessage/ChatUserMessage.tsx +++ b/web/components/chat/ChatUserMessage/ChatUserMessage.tsx @@ -1,18 +1,27 @@ /* eslint-disable react/no-danger */ import { FC, useEffect, useState } from 'react'; -import { Highlight } from 'react-highlighter-ts'; import he from 'he'; import cn from 'classnames'; import { Tooltip } from 'antd'; import { LinkOutlined } from '@ant-design/icons'; import { useRecoilValue } from 'recoil'; +import dynamic from 'next/dynamic'; import styles from './ChatUserMessage.module.scss'; import { formatTimestamp } from './messageFmt'; import { ChatMessage } from '../../../interfaces/chat-message.model'; -import { ChatModerationActionMenu } from '../ChatModerationActionMenu/ChatModerationActionMenu'; import { ChatUserBadge } from '../ChatUserBadge/ChatUserBadge'; import { accessTokenAtom } from '../../stores/ClientConfigStore'; +// Lazy loaded components + +const ChatModerationActionMenu = dynamic(() => + import('../ChatModerationActionMenu/ChatModerationActionMenu').then( + mod => mod.ChatModerationActionMenu, + ), +); + +const Highlight = dynamic(() => import('react-highlighter-ts').then(mod => mod.Highlight)); + export type ChatUserMessageProps = { message: ChatMessage; showModeratorMenu: boolean; diff --git a/web/components/common/UserDropdown/UserDropdown.tsx b/web/components/common/UserDropdown/UserDropdown.tsx index c4a40b4383..0e2f93561a 100644 --- a/web/components/common/UserDropdown/UserDropdown.tsx +++ b/web/components/common/UserDropdown/UserDropdown.tsx @@ -9,16 +9,25 @@ import { import { useRecoilState, useRecoilValue } from 'recoil'; import { FC, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; -import { Modal } from '../../ui/Modal/Modal'; +import dynamic from 'next/dynamic'; import { chatVisibleToggleAtom, chatDisplayNameAtom, appStateAtom, } from '../../stores/ClientConfigStore'; import styles from './UserDropdown.module.scss'; -import { NameChangeModal } from '../../modals/NameChangeModal/NameChangeModal'; import { AppStateOptions } from '../../stores/application-state'; -import { AuthModal } from '../../modals/AuthModal/AuthModal'; + +// Lazy loaded components +const Modal = dynamic(() => import('../../ui/Modal/Modal').then(mod => mod.Modal)); + +const NameChangeModal = dynamic(() => + import('../../modals/NameChangeModal/NameChangeModal').then(mod => mod.NameChangeModal), +); + +const AuthModal = dynamic(() => + import('../../modals/AuthModal/AuthModal').then(mod => mod.AuthModal), +); export type UserDropdownProps = { username?: string; diff --git a/web/components/ui/Content/Content.tsx b/web/components/ui/Content/Content.tsx index a923817274..577b72de5c 100644 --- a/web/components/ui/Content/Content.tsx +++ b/web/components/ui/Content/Content.tsx @@ -2,6 +2,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'; import { Layout, Tabs, Spin } from 'antd'; import { FC, useEffect, useState } from 'react'; import classNames from 'classnames'; +import dynamic from 'next/dynamic'; import { LOCAL_STORAGE_KEYS, getLocalStorage, setLocalStorage } from '../../../utils/localStorage'; import { @@ -19,29 +20,46 @@ import { import { ClientConfig } from '../../../interfaces/client-config.model'; import { CustomPageContent } from '../CustomPageContent/CustomPageContent'; import { OwncastPlayer } from '../../video/OwncastPlayer/OwncastPlayer'; -import { FollowerCollection } from '../followers/FollowerCollection/FollowerCollection'; import styles from './Content.module.scss'; import { Sidebar } from '../Sidebar/Sidebar'; import { Footer } from '../Footer/Footer'; import { ActionButtonRow } from '../../action-buttons/ActionButtonRow/ActionButtonRow'; import { ActionButton } from '../../action-buttons/ActionButton/ActionButton'; -import { NotifyReminderPopup } from '../NotifyReminderPopup/NotifyReminderPopup'; import { OfflineBanner } from '../OfflineBanner/OfflineBanner'; import { AppStateOptions } from '../../stores/application-state'; import { FollowButton } from '../../action-buttons/FollowButton'; import { NotifyButton } from '../../action-buttons/NotifyButton'; -import { Modal } from '../Modal/Modal'; -import { BrowserNotifyModal } from '../../modals/BrowserNotifyModal/BrowserNotifyModal'; import { ContentHeader } from '../../common/ContentHeader/ContentHeader'; import { ServerStatus } from '../../../interfaces/server-status.model'; import { Statusbar } from '../Statusbar/Statusbar'; -import { ChatContainer } from '../../chat/ChatContainer/ChatContainer'; import { ChatMessage } from '../../../interfaces/chat-message.model'; const { TabPane } = Tabs; const { Content: AntContent } = Layout; +// Lazy loaded components + +const Modal = dynamic(() => import('../Modal/Modal').then(mod => mod.Modal)); + +const BrowserNotifyModal = dynamic(() => + import('../../modals/BrowserNotifyModal/BrowserNotifyModal').then(mod => mod.BrowserNotifyModal), +); + +const NotifyReminderPopup = dynamic(() => + import('../NotifyReminderPopup/NotifyReminderPopup').then(mod => mod.NotifyReminderPopup), +); + +const FollowerCollection = dynamic(() => + import('../followers/FollowerCollection/FollowerCollection').then(mod => mod.FollowerCollection), +); + +// We only need to load the chat container here if we're in mobile or narrow +// windows, so lazy loading it makes sense. +const ChatContainer = dynamic(() => + import('../../chat/ChatContainer/ChatContainer').then(mod => mod.ChatContainer), +); + const DesktopContent = ({ name, streamTitle, summary, tags, socialHandles, extraPageContent }) => ( <>