diff --git a/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.tsx b/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.tsx index 972849221..afcc189b1 100644 --- a/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.tsx +++ b/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.tsx @@ -1,10 +1,24 @@ import { FC } from 'react'; import { Button, Dropdown, Menu } from 'antd'; import classNames from 'classnames'; -import { EllipsisOutlined, HeartOutlined, BellOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import styles from './ActionButtonMenu.module.scss'; import { ExternalAction } from '../../../interfaces/external-action'; +// Lazy loaded components + +const EllipsisOutlined = dynamic(() => import('@ant-design/icons/EllipsisOutlined'), { + ssr: false, +}); + +const HeartOutlined = dynamic(() => import('@ant-design/icons/HeartOutlined'), { + ssr: false, +}); + +const BellOutlined = dynamic(() => import('@ant-design/icons/BellOutlined'), { + ssr: false, +}); + const NOTIFY_KEY = 'notify'; const FOLLOW_KEY = 'follow'; diff --git a/web/components/action-buttons/FollowButton.tsx b/web/components/action-buttons/FollowButton.tsx index e1a644b36..148194d90 100644 --- a/web/components/action-buttons/FollowButton.tsx +++ b/web/components/action-buttons/FollowButton.tsx @@ -1,9 +1,15 @@ import { Button, ButtonProps } from 'antd'; -import { HeartFilled } from '@ant-design/icons'; import { FC } from 'react'; +import dynamic from 'next/dynamic'; import styles from './ActionButton/ActionButton.module.scss'; +// Lazy loaded components + +const HeartFilled = dynamic(() => import('@ant-design/icons/HeartFilled'), { + ssr: false, +}); + export type FollowButtonProps = ButtonProps & { onClick?: () => void; props?: ButtonProps; diff --git a/web/components/action-buttons/NotifyButton.tsx b/web/components/action-buttons/NotifyButton.tsx index 127052874..3bc349b2c 100644 --- a/web/components/action-buttons/NotifyButton.tsx +++ b/web/components/action-buttons/NotifyButton.tsx @@ -1,8 +1,14 @@ import { Button } from 'antd'; -import { BellFilled } from '@ant-design/icons'; import { FC } from 'react'; +import dynamic from 'next/dynamic'; import styles from './ActionButton/ActionButton.module.scss'; +// Lazy loaded components + +const BellFilled = dynamic(() => import('@ant-design/icons/BellFilled'), { + ssr: false, +}); + export type NotifyButtonProps = { text?: string; onClick?: () => void; diff --git a/web/components/admin/BanUserButton.tsx b/web/components/admin/BanUserButton.tsx index 63cc2649b..8201662a3 100644 --- a/web/components/admin/BanUserButton.tsx +++ b/web/components/admin/BanUserButton.tsx @@ -1,9 +1,23 @@ import { Modal, Button } from 'antd'; -import { ExclamationCircleFilled, QuestionCircleFilled, StopTwoTone } from '@ant-design/icons'; import { FC } from 'react'; +import dynamic from 'next/dynamic'; import { USER_ENABLED_TOGGLE, fetchData } from '../../utils/apis'; import { User } from '../../types/chat'; +// Lazy loaded components + +const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { + ssr: false, +}); + +const QuestionCircleFilled = dynamic(() => import('@ant-design/icons/QuestionCircleFilled'), { + ssr: false, +}); + +const StopTwoTone = dynamic(() => import('@ant-design/icons/StopTwoTone'), { + ssr: false, +}); + export type BanUserButtonProps = { user: User; isEnabled: Boolean; // = this user's current status diff --git a/web/components/admin/BannedIPsTable.tsx b/web/components/admin/BannedIPsTable.tsx index 725b10e20..3de714367 100644 --- a/web/components/admin/BannedIPsTable.tsx +++ b/web/components/admin/BannedIPsTable.tsx @@ -2,10 +2,16 @@ import { Table, Button } from 'antd'; import format from 'date-fns/format'; import { SortOrder } from 'antd/lib/table/interface'; import React, { FC } from 'react'; -import { StopTwoTone } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { User } from '../../types/chat'; import { BANNED_IP_REMOVE, fetchData } from '../../utils/apis'; +// Lazy loaded components + +const StopTwoTone = dynamic(() => import('@ant-design/icons/StopTwoTone'), { + ssr: false, +}); + function formatDisplayDate(date: string | Date) { return format(new Date(date), 'MMM d H:mma'); } diff --git a/web/components/admin/ClientTable.tsx b/web/components/admin/ClientTable.tsx index 38ece5af6..495a601b9 100644 --- a/web/components/admin/ClientTable.tsx +++ b/web/components/admin/ClientTable.tsx @@ -1,14 +1,20 @@ import { Input, Table } from 'antd'; import { FilterDropdownProps, SortOrder } from 'antd/lib/table/interface'; import { ColumnsType } from 'antd/es/table'; -import { SearchOutlined } from '@ant-design/icons'; import { formatDistanceToNow } from 'date-fns'; import { FC } from 'react'; +import dynamic from 'next/dynamic'; import { Client } from '../../types/chat'; import { UserPopover } from './UserPopover'; import { BanUserButton } from './BanUserButton'; import { formatUAstring } from '../../utils/format'; +// Lazy loaded components + +const SearchOutlined = dynamic(() => import('@ant-design/icons/SearchOutlined'), { + ssr: false, +}); + export type ClientTableProps = { data: Client[]; }; diff --git a/web/components/admin/CurrentVariantsTable.tsx b/web/components/admin/CurrentVariantsTable.tsx index f2d730ee9..d6d67c813 100644 --- a/web/components/admin/CurrentVariantsTable.tsx +++ b/web/components/admin/CurrentVariantsTable.tsx @@ -3,7 +3,7 @@ import React, { FC, useContext, useState } from 'react'; import { Typography, Table, Modal, Button, Alert } from 'antd'; import { ColumnsType } from 'antd/lib/table'; -import { DeleteOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { ServerStatusContext } from '../../utils/server-status-context'; import { AlertMessageContext } from '../../utils/alert-message-context'; import { UpdateArgs, VideoVariant } from '../../types/config-section'; @@ -28,6 +28,12 @@ import { FormStatusIndicator } from './FormStatusIndicator'; const { Title } = Typography; +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + // eslint-disable-next-line import/prefer-default-export export const CurrentVariantsTable: FC = () => { const [displayModal, setDisplayModal] = useState(false); diff --git a/web/components/admin/EditInstanceDetails2.tsx b/web/components/admin/EditInstanceDetails2.tsx index 87c42b316..f27f8e5d1 100644 --- a/web/components/admin/EditInstanceDetails2.tsx +++ b/web/components/admin/EditInstanceDetails2.tsx @@ -1,6 +1,6 @@ import React, { useState, useContext, useEffect } from 'react'; import { Button, Collapse, Typography, Tooltip } from 'antd'; -import { CopyOutlined, RedoOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { TEXTFIELD_TYPE_NUMBER, TEXTFIELD_TYPE_PASSWORD, TEXTFIELD_TYPE_URL } from './TextField'; import { TextFieldWithSubmit } from './TextFieldWithSubmit'; import { ServerStatusContext } from '../../utils/server-status-context'; @@ -17,6 +17,14 @@ import { ResetYP } from './ResetYP'; // Lazy loaded components +const CopyOutlined = dynamic(() => import('@ant-design/icons/CopyOutlined'), { + ssr: false, +}); + +const RedoOutlined = dynamic(() => import('@ant-design/icons/RedoOutlined'), { + ssr: false, +}); + const { Panel } = Collapse; // eslint-disable-next-line react/function-component-definition diff --git a/web/components/admin/EditLogo.tsx b/web/components/admin/EditLogo.tsx index 49be45435..c154767ad 100644 --- a/web/components/admin/EditLogo.tsx +++ b/web/components/admin/EditLogo.tsx @@ -1,7 +1,7 @@ import { Button, Upload } from 'antd'; import { RcFile } from 'antd/lib/upload/interface'; -import { LoadingOutlined, UploadOutlined } from '@ant-design/icons'; import React, { useState, useContext, FC } from 'react'; +import dynamic from 'next/dynamic'; import { FormStatusIndicator } from './FormStatusIndicator'; import { ServerStatusContext } from '../../utils/server-status-context'; import { @@ -25,6 +25,16 @@ import { readableBytes, } from '../../utils/images'; +// Lazy loaded components + +const LoadingOutlined = dynamic(() => import('@ant-design/icons/LoadingOutlined'), { + ssr: false, +}); + +const UploadOutlined = dynamic(() => import('@ant-design/icons/UploadOutlined'), { + ssr: false, +}); + // eslint-disable-next-line import/prefer-default-export export const EditLogo: FC = () => { const [logoUrl, setlogoUrl] = useState(null); diff --git a/web/components/admin/InfoTip.tsx b/web/components/admin/InfoTip.tsx index 7dd12d012..bd006c61c 100644 --- a/web/components/admin/InfoTip.tsx +++ b/web/components/admin/InfoTip.tsx @@ -1,7 +1,13 @@ -import { InfoCircleOutlined } from '@ant-design/icons'; import { Tooltip } from 'antd'; +import dynamic from 'next/dynamic'; import { FC } from 'react'; +// Lazy loaded components + +const InfoCircleOutlined = dynamic(() => import('@ant-design/icons/InfoCircleOutlined'), { + ssr: false, +}); + export type InfoTipProps = { tip: string | null; }; diff --git a/web/components/admin/MainLayout.tsx b/web/components/admin/MainLayout.tsx index 6763f11d5..aab50b93d 100644 --- a/web/components/admin/MainLayout.tsx +++ b/web/components/admin/MainLayout.tsx @@ -5,20 +5,9 @@ import Head from 'next/head'; import { differenceInSeconds } from 'date-fns'; import { useRouter } from 'next/router'; import { Layout, Menu, Alert, Button, Space, Tooltip } from 'antd'; -import { - SettingOutlined, - HomeOutlined, - LineChartOutlined, - ToolOutlined, - PlayCircleFilled, - MinusSquareFilled, - QuestionCircleOutlined, - MessageOutlined, - ExperimentOutlined, - EditOutlined, -} from '@ant-design/icons'; import classNames from 'classnames'; +import dynamic from 'next/dynamic'; import { upgradeVersionAvailable } from '../../utils/apis'; import { parseSecondsToDurationString } from '../../utils/format'; @@ -31,6 +20,48 @@ import { TEXTFIELD_PROPS_STREAM_TITLE } from '../../utils/config-constants'; import { ComposeFederatedPost } from './ComposeFederatedPost'; import { UpdateArgs } from '../../types/config-section'; +// Lazy loaded components + +const SettingOutlined = dynamic(() => import('@ant-design/icons/SettingOutlined'), { + ssr: false, +}); // Lazy loaded components + +const HomeOutlined = dynamic(() => import('@ant-design/icons/HomeOutlined'), { + ssr: false, +}); + +const LineChartOutlined = dynamic(() => import('@ant-design/icons/LineChartOutlined'), { + ssr: false, +}); + +const ToolOutlined = dynamic(() => import('@ant-design/icons/ToolOutlined'), { + ssr: false, +}); + +const PlayCircleFilled = dynamic(() => import('@ant-design/icons/PlayCircleFilled'), { + ssr: false, +}); + +const MinusSquareFilled = dynamic(() => import('@ant-design/icons/MinusSquareFilled'), { + ssr: false, +}); + +const QuestionCircleOutlined = dynamic(() => import('@ant-design/icons/QuestionCircleOutlined'), { + ssr: false, +}); + +const MessageOutlined = dynamic(() => import('@ant-design/icons/MessageOutlined'), { + ssr: false, +}); + +const ExperimentOutlined = dynamic(() => import('@ant-design/icons/ExperimentOutlined'), { + ssr: false, +}); + +const EditOutlined = dynamic(() => import('@ant-design/icons/EditOutlined'), { + ssr: false, +}); + export type MainLayoutProps = { children: ReactNode; }; diff --git a/web/components/admin/MessageVisiblityToggle.tsx b/web/components/admin/MessageVisiblityToggle.tsx index e26e6ecb1..0de5f170b 100644 --- a/web/components/admin/MessageVisiblityToggle.tsx +++ b/web/components/admin/MessageVisiblityToggle.tsx @@ -1,16 +1,30 @@ // Custom component for AntDesign Button that makes an api call, then displays a confirmation icon upon import React, { useState, useEffect, FC } from 'react'; import { Button, Tooltip } from 'antd'; -import { - EyeOutlined, - EyeInvisibleOutlined, - CheckCircleFilled, - ExclamationCircleFilled, -} from '@ant-design/icons'; + +import dynamic from 'next/dynamic'; import { fetchData, UPDATE_CHAT_MESSGAE_VIZ } from '../../utils/apis'; import { MessageType } from '../../types/chat'; import { isEmptyObject } from '../../utils/format'; +// Lazy loaded components + +const EyeOutlined = dynamic(() => import('@ant-design/icons/EyeOutlined'), { + ssr: false, +}); + +const EyeInvisibleOutlined = dynamic(() => import('@ant-design/icons/EyeInvisibleOutlined'), { + ssr: false, +}); + +const CheckCircleFilled = dynamic(() => import('@ant-design/icons/CheckCircleFilled'), { + ssr: false, +}); + +const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { + ssr: false, +}); + export type MessageToggleProps = { isVisible: boolean; message: MessageType; diff --git a/web/components/admin/ModeratorUserButton.tsx b/web/components/admin/ModeratorUserButton.tsx index a7a4cc396..f856a8419 100644 --- a/web/components/admin/ModeratorUserButton.tsx +++ b/web/components/admin/ModeratorUserButton.tsx @@ -1,14 +1,31 @@ import { Modal, Button } from 'antd'; -import { - ExclamationCircleFilled, - QuestionCircleFilled, - StopTwoTone, - SafetyCertificateTwoTone, -} from '@ant-design/icons'; + import { FC } from 'react'; +import dynamic from 'next/dynamic'; import { USER_SET_MODERATOR, fetchData } from '../../utils/apis'; import { User } from '../../types/chat'; +// Lazy loaded components + +const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { + ssr: false, +}); + +const QuestionCircleFilled = dynamic(() => import('@ant-design/icons/QuestionCircleFilled'), { + ssr: false, +}); + +const StopTwoTone = dynamic(() => import('@ant-design/icons/StopTwoTone'), { + ssr: false, +}); + +const SafetyCertificateTwoTone = dynamic( + () => import('@ant-design/icons/SafetyCertificateTwoTone'), + { + ssr: false, + }, +); + export type ModeratorUserButtonProps = { user: User; onClick?: () => void; diff --git a/web/components/admin/Offline.tsx b/web/components/admin/Offline.tsx index c96b1b387..ba50a019f 100644 --- a/web/components/admin/Offline.tsx +++ b/web/components/admin/Offline.tsx @@ -1,7 +1,7 @@ -import { BookTwoTone, MessageTwoTone, PlaySquareTwoTone, ProfileTwoTone } from '@ant-design/icons'; import { Card, Col, Row, Typography } from 'antd'; import Link from 'next/link'; import { FC, useContext } from 'react'; +import dynamic from 'next/dynamic'; import { LogTable } from './LogTable'; import { OwncastLogo } from '../common/OwncastLogo/OwncastLogo'; import { NewsFeed } from './NewsFeed'; @@ -13,6 +13,24 @@ const { Paragraph, Text } = Typography; const { Title } = Typography; const { Meta } = Card; +// Lazy loaded components + +const BookTwoTone = dynamic(() => import('@ant-design/icons/BookTwoTone'), { + ssr: false, +}); + +const MessageTwoTone = dynamic(() => import('@ant-design/icons/MessageTwoTone'), { + ssr: false, +}); + +const PlaySquareTwoTone = dynamic(() => import('@ant-design/icons/PlaySquareTwoTone'), { + ssr: false, +}); + +const ProfileTwoTone = dynamic(() => import('@ant-design/icons/ProfileTwoTone'), { + ssr: false, +}); + function generateStreamURL(serverURL, rtmpServerPort) { return `rtmp://${serverURL.replace(/(^\w+:|^)\/\//, '')}:${rtmpServerPort}/live`; } diff --git a/web/components/admin/StreamHealthOverview.tsx b/web/components/admin/StreamHealthOverview.tsx index 73a27095c..8855e437d 100644 --- a/web/components/admin/StreamHealthOverview.tsx +++ b/web/components/admin/StreamHealthOverview.tsx @@ -1,9 +1,22 @@ -import { CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import { Alert, Button, Col, Row, Statistic, Typography } from 'antd'; +import dynamic from 'next/dynamic'; import Link from 'next/link'; import React, { FC, useContext } from 'react'; import { ServerStatusContext } from '../../utils/server-status-context'; +// Lazy loaded components + +const CheckCircleOutlined = dynamic(() => import('@ant-design/icons/CheckCircleOutlined'), { + ssr: false, +}); + +const ExclamationCircleOutlined = dynamic( + () => import('@ant-design/icons/ExclamationCircleOutlined'), + { + ssr: false, + }, +); + export type StreamHealthOverviewProps = { showTroubleshootButton?: Boolean; }; diff --git a/web/components/admin/VideoVariantForm.tsx b/web/components/admin/VideoVariantForm.tsx index 3bebf45c0..c90554e04 100644 --- a/web/components/admin/VideoVariantForm.tsx +++ b/web/components/admin/VideoVariantForm.tsx @@ -1,8 +1,8 @@ // This content populates the video variant modal, which is spawned from the variants table. This relies on the `dataState` prop fed in by the table. import React, { FC } from 'react'; import { Popconfirm, Row, Col, Slider, Collapse, Typography, Alert, Button } from 'antd'; -import { ExclamationCircleFilled } from '@ant-design/icons'; import classNames from 'classnames'; +import dynamic from 'next/dynamic'; import { FieldUpdaterFunc, VideoVariant, UpdateArgs } from '../../types/config-section'; import { TextField } from './TextField'; import { @@ -21,6 +21,12 @@ import { ToggleSwitch } from './ToggleSwitch'; const { Panel } = Collapse; +// Lazy loaded components + +const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { + ssr: false, +}); + export type VideoVariantFormProps = { dataState: VideoVariant; onUpdateField: FieldUpdaterFunc; diff --git a/web/components/admin/config/general/EditSocialLinks.tsx b/web/components/admin/config/general/EditSocialLinks.tsx index 7786c7f81..a3e4fedeb 100644 --- a/web/components/admin/config/general/EditSocialLinks.tsx +++ b/web/components/admin/config/general/EditSocialLinks.tsx @@ -1,7 +1,7 @@ import React, { useState, useContext, useEffect } from 'react'; import { Typography, Table, Button, Modal, Input } from 'antd'; import { ColumnsType } from 'antd/lib/table'; -import { CaretDownOutlined, CaretUpOutlined, DeleteOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { SocialDropdown } from '../../SocialDropdown'; import { fetchData, SOCIAL_PLATFORMS_LIST } from '../../../../utils/apis'; import { ServerStatusContext } from '../../../../utils/server-status-context'; @@ -25,6 +25,20 @@ import { FormStatusIndicator } from '../../FormStatusIndicator'; const { Title } = Typography; +// Lazy loaded components + +const CaretDownOutlined = dynamic(() => import('@ant-design/icons/CaretDownOutlined'), { + ssr: false, +}); + +const CaretUpOutlined = dynamic(() => import('@ant-design/icons/CaretUpOutlined'), { + ssr: false, +}); + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + // eslint-disable-next-line react/function-component-definition export default function EditSocialLinks() { const [availableIconsList, setAvailableIconsList] = useState([]); diff --git a/web/components/admin/config/server/StreamKeys.tsx b/web/components/admin/config/server/StreamKeys.tsx index aac9b5b3e..0f8f78979 100644 --- a/web/components/admin/config/server/StreamKeys.tsx +++ b/web/components/admin/config/server/StreamKeys.tsx @@ -1,6 +1,6 @@ import React, { useContext, useState } from 'react'; import { Table, Space, Button, Typography, Alert, Input, Form } from 'antd'; -import { DeleteOutlined, EyeOutlined, PlusOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { ServerStatusContext } from '../../../../utils/server-status-context'; import { fetchData, UPDATE_STREAM_KEYS } from '../../../../utils/apis'; @@ -8,6 +8,20 @@ import { fetchData, UPDATE_STREAM_KEYS } from '../../../../utils/apis'; const { Paragraph } = Typography; const { Item } = Form; +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + +const EyeOutlined = dynamic(() => import('@ant-design/icons/EyeOutlined'), { + ssr: false, +}); + +const PlusOutlined = dynamic(() => import('@ant-design/icons/PlusOutlined'), { + ssr: false, +}); + const saveKeys = async (keys, setError) => { try { await fetchData(UPDATE_STREAM_KEYS, { diff --git a/web/components/chat/ChatContainer/ChatContainer.tsx b/web/components/chat/ChatContainer/ChatContainer.tsx index db1c05bc8..5d6582bad 100644 --- a/web/components/chat/ChatContainer/ChatContainer.tsx +++ b/web/components/chat/ChatContainer/ChatContainer.tsx @@ -1,6 +1,6 @@ import { Virtuoso } from 'react-virtuoso'; import { useState, useMemo, useRef, CSSProperties, FC, useEffect } from 'react'; -import { EditFilled } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { ConnectedClientInfoEvent, MessageType, @@ -17,6 +17,11 @@ import { ChatJoinMessage } from '../ChatJoinMessage/ChatJoinMessage'; import { ScrollToBotBtn } from './ScrollToBotBtn'; import { ChatActionMessage } from '../ChatActionMessage/ChatActionMessage'; +// Lazy loaded components + +const EditFilled = dynamic(() => import('@ant-design/icons/EditFilled'), { + ssr: false, +}); export type ChatContainerProps = { messages: ChatMessage[]; usernameToHighlight: string; diff --git a/web/components/chat/ChatContainer/ScrollToBotBtn.tsx b/web/components/chat/ChatContainer/ScrollToBotBtn.tsx index 7f6ecf6ba..2a6350f32 100644 --- a/web/components/chat/ChatContainer/ScrollToBotBtn.tsx +++ b/web/components/chat/ChatContainer/ScrollToBotBtn.tsx @@ -1,9 +1,17 @@ -import { VerticalAlignBottomOutlined } from '@ant-design/icons'; import { Button } from 'antd'; +import dynamic from 'next/dynamic'; import { FC, MutableRefObject } from 'react'; import { ChatMessage } from '../../../interfaces/chat-message.model'; import styles from './ChatContainer.module.scss'; +// Lazy loaded components + +const VerticalAlignBottomOutlined = dynamic( + () => import('@ant-design/icons/VerticalAlignBottomOutlined'), + { + ssr: false, + }, +); type Props = { chatContainerRef: MutableRefObject; messages: ChatMessage[]; diff --git a/web/components/chat/ChatJoinMessage/ChatJoinMessage.tsx b/web/components/chat/ChatJoinMessage/ChatJoinMessage.tsx index 572a866cc..3176d1cf6 100644 --- a/web/components/chat/ChatJoinMessage/ChatJoinMessage.tsx +++ b/web/components/chat/ChatJoinMessage/ChatJoinMessage.tsx @@ -1,8 +1,14 @@ import { FC } from 'react'; -import { TeamOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { ChatUserBadge } from '../ChatUserBadge/ChatUserBadge'; import styles from './ChatJoinMessage.module.scss'; +// Lazy loaded components + +const TeamOutlined = dynamic(() => import('@ant-design/icons/TeamOutlined'), { + ssr: false, +}); + export type ChatJoinMessageProps = { isAuthorModerator: boolean; userColor: number; diff --git a/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.tsx b/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.tsx index 8b4c275c1..a71eb8737 100644 --- a/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.tsx +++ b/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.tsx @@ -1,11 +1,6 @@ -import { - CloseCircleOutlined, - ExclamationCircleOutlined, - EyeInvisibleOutlined, - SmallDashOutlined, -} from '@ant-design/icons'; import { Dropdown, Menu, MenuProps, Space, message, Modal as AntModal } from 'antd'; import { FC, useState } from 'react'; +import dynamic from 'next/dynamic'; import { Modal } from '../../ui/Modal/Modal'; import { ChatModerationDetailsModal } from '../ChatModerationDetailsModal/ChatModerationDetailsModal'; import styles from './ChatModerationActionMenu.module.scss'; @@ -13,6 +8,27 @@ import ChatModeration from '../../../services/moderation-service'; const { confirm } = AntModal; +// Lazy loaded components + +const CloseCircleOutlined = dynamic(() => import('@ant-design/icons/CloseCircleOutlined'), { + ssr: false, +}); + +const ExclamationCircleOutlined = dynamic( + () => import('@ant-design/icons/ExclamationCircleOutlined'), + { + ssr: false, + }, +); + +const EyeInvisibleOutlined = dynamic(() => import('@ant-design/icons/EyeInvisibleOutlined'), { + ssr: false, +}); + +const SmallDashOutlined = dynamic(() => import('@ant-design/icons/SmallDashOutlined'), { + ssr: false, +}); + export type ChatModerationActionMenuProps = { accessToken: string; messageID: string; diff --git a/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.tsx b/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.tsx index e755590dc..4d506b227 100644 --- a/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.tsx +++ b/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.tsx @@ -1,14 +1,20 @@ import { Button, Col, Collapse, Row, Spin, Table, Tag } from 'antd'; import { FC, useEffect, useState } from 'react'; import format from 'date-fns/format'; -import { DeleteOutlined } from '@ant-design/icons'; import { ColumnsType } from 'antd/lib/table'; +import dynamic from 'next/dynamic'; import ChatModeration from '../../../services/moderation-service'; import styles from './ChatModerationDetailsModal.module.scss'; import { formatUAstring } from '../../../utils/format'; const { Panel } = Collapse; +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + export type ChatModerationDetailsModalProps = { userId: string; accessToken: string; diff --git a/web/components/chat/ChatTextField/ChatTextField.tsx b/web/components/chat/ChatTextField/ChatTextField.tsx index 0a31bb040..dc244b2c8 100644 --- a/web/components/chat/ChatTextField/ChatTextField.tsx +++ b/web/components/chat/ChatTextField/ChatTextField.tsx @@ -1,4 +1,3 @@ -import { SendOutlined, SmileOutlined } from '@ant-design/icons'; import { Popover } from 'antd'; import React, { FC, useMemo, useState } from 'react'; import { useRecoilValue } from 'recoil'; @@ -17,6 +16,14 @@ const EmojiPicker = dynamic(() => import('./EmojiPicker').then(mod => mod.EmojiP ssr: false, }); +const SendOutlined = dynamic(() => import('@ant-design/icons/SendOutlined'), { + ssr: false, +}); + +const SmileOutlined = dynamic(() => import('@ant-design/icons/SmileOutlined'), { + ssr: false, +}); + 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 6cb1747bc..863e50fec 100644 --- a/web/components/chat/ChatUserMessage/ChatUserMessage.tsx +++ b/web/components/chat/ChatUserMessage/ChatUserMessage.tsx @@ -1,7 +1,6 @@ /* eslint-disable react/no-danger */ import { FC, ReactNode, useEffect, useState } from 'react'; import cn from 'classnames'; -import { LinkOutlined } from '@ant-design/icons'; import { Tooltip } from 'antd'; import { useRecoilValue } from 'recoil'; import dynamic from 'next/dynamic'; @@ -15,6 +14,10 @@ import { User } from '../../../interfaces/user.model'; // Lazy loaded components +const LinkOutlined = dynamic(() => import('@ant-design/icons/LinkOutlined'), { + ssr: false, +}); + const ChatModerationActionMenu = dynamic( () => import('../ChatModerationActionMenu/ChatModerationActionMenu').then( diff --git a/web/components/common/UserDropdown/UserDropdown.tsx b/web/components/common/UserDropdown/UserDropdown.tsx index a769c724f..879caddc6 100644 --- a/web/components/common/UserDropdown/UserDropdown.tsx +++ b/web/components/common/UserDropdown/UserDropdown.tsx @@ -1,11 +1,5 @@ import { Menu, Dropdown, Button } from 'antd'; -import { - CaretDownOutlined, - EditOutlined, - LockOutlined, - MessageOutlined, - UserOutlined, -} from '@ant-design/icons'; + import { useRecoilState, useRecoilValue } from 'recoil'; import { FC, useState } from 'react'; import { useHotkeys } from 'react-hotkeys-hook'; @@ -19,6 +13,27 @@ import styles from './UserDropdown.module.scss'; import { AppStateOptions } from '../../stores/application-state'; // Lazy loaded components + +const CaretDownOutlined = dynamic(() => import('@ant-design/icons/CaretDownOutlined'), { + ssr: false, +}); + +const EditOutlined = dynamic(() => import('@ant-design/icons/EditOutlined'), { + ssr: false, +}); + +const LockOutlined = dynamic(() => import('@ant-design/icons/LockOutlined'), { + ssr: false, +}); + +const MessageOutlined = dynamic(() => import('@ant-design/icons/MessageOutlined'), { + ssr: false, +}); + +const UserOutlined = dynamic(() => import('@ant-design/icons/UserOutlined'), { + ssr: false, +}); + const Modal = dynamic(() => import('../../ui/Modal/Modal').then(mod => mod.Modal), { ssr: false, }); diff --git a/web/components/modals/FediAuthModal/FediAuthModal.tsx b/web/components/modals/FediAuthModal/FediAuthModal.tsx index b9bea9a5a..2ac423571 100644 --- a/web/components/modals/FediAuthModal/FediAuthModal.tsx +++ b/web/components/modals/FediAuthModal/FediAuthModal.tsx @@ -1,11 +1,17 @@ import { Alert, Button, Input, Space, Spin, Collapse } from 'antd'; import React, { FC, useState } from 'react'; -import { CheckCircleOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import styles from './FediAuthModal.module.scss'; import { validateAccount } from '../../../utils/validators'; const { Panel } = Collapse; +// Lazy loaded components + +const CheckCircleOutlined = dynamic(() => import('@ant-design/icons/CheckCircleOutlined'), { + ssr: false, +}); + export type FediAuthModalProps = { authenticated: boolean; displayName: string; diff --git a/web/components/modals/IndieAuthModal/IndieAuthModal.tsx b/web/components/modals/IndieAuthModal/IndieAuthModal.tsx index 2eb102dc1..37e541f05 100644 --- a/web/components/modals/IndieAuthModal/IndieAuthModal.tsx +++ b/web/components/modals/IndieAuthModal/IndieAuthModal.tsx @@ -1,11 +1,17 @@ -import { CheckCircleOutlined } from '@ant-design/icons'; import { Alert, Input, Space, Spin, Collapse, Typography, Button } from 'antd'; +import dynamic from 'next/dynamic'; import React, { FC, useState } from 'react'; import { isValidUrl } from '../../../utils/urls'; const { Panel } = Collapse; const { Link } = Typography; +// Lazy loaded components + +const CheckCircleOutlined = dynamic(() => import('@ant-design/icons/CheckCircleOutlined'), { + ssr: false, +}); + export type IndieAuthModalProps = { authenticated: boolean; displayName: string; diff --git a/web/components/ui/NotifyReminderPopup/NotifyReminderPopup.tsx b/web/components/ui/NotifyReminderPopup/NotifyReminderPopup.tsx index ab1690022..707273988 100644 --- a/web/components/ui/NotifyReminderPopup/NotifyReminderPopup.tsx +++ b/web/components/ui/NotifyReminderPopup/NotifyReminderPopup.tsx @@ -1,8 +1,14 @@ import { Popover } from 'antd'; -import { CloseOutlined } from '@ant-design/icons'; import React, { useState, useEffect, FC } from 'react'; +import dynamic from 'next/dynamic'; import styles from './NotifyReminderPopup.module.scss'; +// Lazy loaded components + +const CloseOutlined = dynamic(() => import('@ant-design/icons/CloseOutlined'), { + ssr: false, +}); + export type NotifyReminderPopupProps = { open: boolean; children: React.ReactNode; diff --git a/web/components/ui/OfflineBanner/OfflineBanner.tsx b/web/components/ui/OfflineBanner/OfflineBanner.tsx index b8a84f74f..8047695b8 100644 --- a/web/components/ui/OfflineBanner/OfflineBanner.tsx +++ b/web/components/ui/OfflineBanner/OfflineBanner.tsx @@ -1,10 +1,16 @@ /* eslint-disable jsx-a11y/click-events-have-key-events */ import { Divider } from 'antd'; -import { ClockCircleOutlined } from '@ant-design/icons'; import { FC } from 'react'; import formatDistanceToNow from 'date-fns/formatDistanceToNow'; +import dynamic from 'next/dynamic'; import styles from './OfflineBanner.module.scss'; +// Lazy loaded components + +const ClockCircleOutlined = dynamic(() => import('@ant-design/icons/ClockCircleOutlined'), { + ssr: false, +}); + export type OfflineBannerProps = { streamName: string; customText?: string; diff --git a/web/components/ui/Statusbar/Statusbar.tsx b/web/components/ui/Statusbar/Statusbar.tsx index 9e84b9356..43a98dad7 100644 --- a/web/components/ui/Statusbar/Statusbar.tsx +++ b/web/components/ui/Statusbar/Statusbar.tsx @@ -1,9 +1,15 @@ import formatDistanceToNow from 'date-fns/formatDistanceToNow'; import intervalToDuration from 'date-fns/intervalToDuration'; import { FC, useEffect, useState } from 'react'; -import { EyeFilled } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import styles from './Statusbar.module.scss'; +// Lazy loaded components + +const EyeFilled = dynamic(() => import('@ant-design/icons/EyeFilled'), { + ssr: false, +}); + export type StatusbarProps = { online: Boolean; lastConnectTime?: Date; diff --git a/web/pages/admin/access-tokens.tsx b/web/pages/admin/access-tokens.tsx index 2973bc5b8..f78723f43 100644 --- a/web/pages/admin/access-tokens.tsx +++ b/web/pages/admin/access-tokens.tsx @@ -12,10 +12,10 @@ import { Col, Tooltip, } from 'antd'; -import { DeleteOutlined } from '@ant-design/icons'; import format from 'date-fns/format'; +import dynamic from 'next/dynamic'; import { fetchData, ACCESS_TOKENS, @@ -25,6 +25,12 @@ import { const { Title, Paragraph } = Typography; +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + const availableScopes = { CAN_SEND_SYSTEM_MESSAGES: { name: 'System messages', diff --git a/web/pages/admin/actions.tsx b/web/pages/admin/actions.tsx index 9a56f74a4..5a9f74f63 100644 --- a/web/pages/admin/actions.tsx +++ b/web/pages/admin/actions.tsx @@ -1,6 +1,6 @@ -import { DeleteOutlined, EditOutlined } from '@ant-design/icons'; import { Button, Checkbox, Form, Input, Modal, Space, Table, Typography } from 'antd'; import _ from 'lodash'; +import dynamic from 'next/dynamic'; import React, { useContext, useEffect, useState } from 'react'; import { FormStatusIndicator } from '../../components/admin/FormStatusIndicator'; import { ExternalAction } from '../../interfaces/external-action'; @@ -14,6 +14,17 @@ import { ServerStatusContext } from '../../utils/server-status-context'; import { isValidUrl, DEFAULT_TEXTFIELD_URL_PATTERN } from '../../utils/urls'; const { Title, Paragraph } = Typography; + +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + +const EditOutlined = dynamic(() => import('@ant-design/icons/EditOutlined'), { + ssr: false, +}); + let resetTimer = null; interface Props { diff --git a/web/pages/admin/chat/emojis.tsx b/web/pages/admin/chat/emojis.tsx index ec5e34b08..9ce13f078 100644 --- a/web/pages/admin/chat/emojis.tsx +++ b/web/pages/admin/chat/emojis.tsx @@ -1,7 +1,7 @@ -import { DeleteOutlined } from '@ant-design/icons'; import { Button, Space, Table, Typography, Upload } from 'antd'; import { RcFile } from 'antd/lib/upload'; import React, { useEffect, useState } from 'react'; +import dynamic from 'next/dynamic'; import FormStatusIndicator from '../../../components/admin/FormStatusIndicator'; import { DELETE_EMOJI, fetchData, UPLOAD_EMOJI } from '../../../utils/apis'; @@ -16,6 +16,12 @@ import { import { RESET_TIMEOUT } from '../../../utils/config-constants'; import { URL_CUSTOM_EMOJIS } from '../../../utils/constants'; +// Lazy loaded components + +const DeleteOutlined = dynamic(() => import('@ant-design/icons/DeleteOutlined'), { + ssr: false, +}); + type CustomEmoji = { name: string; url: string; diff --git a/web/pages/admin/chat/messages.tsx b/web/pages/admin/chat/messages.tsx index 727553573..1ebdd703d 100644 --- a/web/pages/admin/chat/messages.tsx +++ b/web/pages/admin/chat/messages.tsx @@ -1,10 +1,10 @@ import React, { useState, useEffect } from 'react'; import { Table, Typography, Button } from 'antd'; -import { CheckCircleFilled, ExclamationCircleFilled } from '@ant-design/icons'; import classNames from 'classnames'; import { ColumnsType } from 'antd/es/table'; import format from 'date-fns/format'; +import dynamic from 'next/dynamic'; import { MessageType } from '../../../types/chat'; import { CHAT_HISTORY, @@ -18,6 +18,16 @@ import { UserPopover } from '../../../components/admin/UserPopover'; const { Title } = Typography; +// Lazy loaded components + +const CheckCircleFilled = dynamic(() => import('@ant-design/icons/CheckCircleFilled'), { + ssr: false, +}); + +const ExclamationCircleFilled = dynamic(() => import('@ant-design/icons/ExclamationCircleFilled'), { + ssr: false, +}); + function createUserNameFilters(messages: MessageType[]) { const filtered = messages.reduce((acc, curItem) => { const curAuthor = curItem.user.id; diff --git a/web/pages/admin/federation/followers.tsx b/web/pages/admin/federation/followers.tsx index 3f095a4d0..d120c8684 100644 --- a/web/pages/admin/federation/followers.tsx +++ b/web/pages/admin/federation/followers.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useContext } from 'react'; import { Table, Avatar, Button, Tabs } from 'antd'; import { ColumnsType, SortOrder } from 'antd/lib/table/interface'; import format from 'date-fns/format'; -import { UserAddOutlined, UserDeleteOutlined } from '@ant-design/icons'; +import dynamic from 'next/dynamic'; import { ServerStatusContext } from '../../../utils/server-status-context'; import { FOLLOWERS, @@ -13,6 +13,15 @@ import { } from '../../../utils/apis'; import { isEmptyObject } from '../../../utils/format'; +// Lazy loaded components + +const UserAddOutlined = dynamic(() => import('@ant-design/icons/UserAddOutlined'), { + ssr: false, +}); + +const UserDeleteOutlined = dynamic(() => import('@ant-design/icons/UserDeleteOutlined'), { + ssr: false, +}); export interface Follower { link: string; username: string; diff --git a/web/pages/admin/hardware-info.tsx b/web/pages/admin/hardware-info.tsx index 702639274..786bfd8b6 100644 --- a/web/pages/admin/hardware-info.tsx +++ b/web/pages/admin/hardware-info.tsx @@ -1,10 +1,24 @@ -import { BulbOutlined, LaptopOutlined, SaveOutlined } from '@ant-design/icons'; import { Row, Col, Typography } from 'antd'; import React, { useEffect, useState } from 'react'; +import dynamic from 'next/dynamic'; import { fetchData, FETCH_INTERVAL, HARDWARE_STATS } from '../../utils/apis'; import { Chart } from '../../components/admin/Chart'; import { StatisticItem } from '../../components/admin/StatisticItem'; +// Lazy loaded components + +const BulbOutlined = dynamic(() => import('@ant-design/icons/BulbOutlined'), { + ssr: false, +}); + +const LaptopOutlined = dynamic(() => import('@ant-design/icons/LaptopOutlined'), { + ssr: false, +}); + +const SaveOutlined = dynamic(() => import('@ant-design/icons/SaveOutlined'), { + ssr: false, +}); + // TODO: FIX TS WARNING FROM THIS. // interface TimedValue { // time: Date; diff --git a/web/pages/admin/help.tsx b/web/pages/admin/help.tsx index 76191d7b0..16d355386 100644 --- a/web/pages/admin/help.tsx +++ b/web/pages/admin/help.tsx @@ -1,19 +1,51 @@ import { Button, Card, Col, Divider, Result, Row } from 'antd'; import Meta from 'antd/lib/card/Meta'; import Title from 'antd/lib/typography/Title'; -import { - ApiTwoTone, - BugTwoTone, - CameraTwoTone, - DatabaseTwoTone, - EditTwoTone, - Html5TwoTone, - LinkOutlined, - QuestionCircleTwoTone, - SettingTwoTone, - SlidersTwoTone, -} from '@ant-design/icons'; + import React from 'react'; +import dynamic from 'next/dynamic'; + +// Lazy loaded components + +const ApiTwoTone = dynamic(() => import('@ant-design/icons/ApiTwoTone'), { + ssr: false, +}); + +const BugTwoTone = dynamic(() => import('@ant-design/icons/BugTwoTone'), { + ssr: false, +}); + +const CameraTwoTone = dynamic(() => import('@ant-design/icons/CameraTwoTone'), { + ssr: false, +}); + +const DatabaseTwoTone = dynamic(() => import('@ant-design/icons/DatabaseTwoTone'), { + ssr: false, +}); + +const EditTwoTone = dynamic(() => import('@ant-design/icons/EditTwoTone'), { + ssr: false, +}); + +const Html5TwoTone = dynamic(() => import('@ant-design/icons/Html5TwoTone'), { + ssr: false, +}); + +const LinkOutlined = dynamic(() => import('@ant-design/icons/LinkOutlined'), { + ssr: false, +}); + +const QuestionCircleTwoTone = dynamic(() => import('@ant-design/icons/QuestionCircleTwoTone'), { + ssr: false, +}); + +const SettingTwoTone = dynamic(() => import('@ant-design/icons/SettingTwoTone'), { + ssr: false, +}); + +const SlidersTwoTone = dynamic(() => import('@ant-design/icons/SlidersTwoTone'), { + ssr: false, +}); export default function Help() { const questions = [ diff --git a/web/pages/admin/index.tsx b/web/pages/admin/index.tsx index 281d0c3d6..a4e796cc9 100644 --- a/web/pages/admin/index.tsx +++ b/web/pages/admin/index.tsx @@ -1,8 +1,8 @@ /* eslint-disable @next/next/no-css-tags */ import React, { useState, useEffect, useContext } from 'react'; import { Skeleton, Card, Statistic, Row, Col } from 'antd'; -import { UserOutlined, ClockCircleOutlined } from '@ant-design/icons'; import { formatDistanceToNow, formatRelative } from 'date-fns'; +import dynamic from 'next/dynamic'; import { ServerStatusContext } from '../../utils/server-status-context'; import { LogTable } from '../../components/admin/LogTable'; import { Offline } from '../../components/admin/Offline'; @@ -12,6 +12,16 @@ import { LOGS_WARN, fetchData, FETCH_INTERVAL } from '../../utils/apis'; import { formatIPAddress, isEmptyObject } from '../../utils/format'; import { NewsFeed } from '../../components/admin/NewsFeed'; +// Lazy loaded components + +const UserOutlined = dynamic(() => import('@ant-design/icons/UserOutlined'), { + ssr: false, +}); + +const ClockCircleOutlined = dynamic(() => import('@ant-design/icons/ClockCircleOutlined'), { + ssr: false, +}); + function streamDetailsFormatter(streamDetails) { return (