From 6b173f44bef134ca37937bf029d7a31c26246e40 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 15:04:37 -0500 Subject: [PATCH 1/7] AsyncComponents: use React.lazy --- .../emoji/components/emoji-picker.tsx | 6 +- src/features/ui/util/async-components.ts | 811 ++++-------------- 2 files changed, 166 insertions(+), 651 deletions(-) diff --git a/src/features/emoji/components/emoji-picker.tsx b/src/features/emoji/components/emoji-picker.tsx index 695fae2cc..6dd2b8064 100644 --- a/src/features/emoji/components/emoji-picker.tsx +++ b/src/features/emoji/components/emoji-picker.tsx @@ -13,7 +13,7 @@ const getImageURL = (set: string, name: string) => { return joinPublicPath(`/packs/emoji/${name}.svg`); }; -const Picker = (props: any) => { +const Picker: React.FC = (props) => { const ref = useRef(null); useEffect(() => { @@ -25,6 +25,4 @@ const Picker = (props: any) => { return
; }; -export { - Picker, -}; +export default Picker; diff --git a/src/features/ui/util/async-components.ts b/src/features/ui/util/async-components.ts index b5208b3e1..a93048aeb 100644 --- a/src/features/ui/util/async-components.ts +++ b/src/features/ui/util/async-components.ts @@ -1,647 +1,164 @@ -export function AboutPage() { - return import('../../about'); -} - -export function EmojiPicker() { - return import('../../emoji/components/emoji-picker'); -} - -export function Notifications() { - return import('../../notifications'); -} - -export function LandingTimeline() { - return import('../../landing-timeline'); -} - -export function HomeTimeline() { - return import('../../home-timeline'); -} - -export function PublicTimeline() { - return import('../../public-timeline'); -} - -export function RemoteTimeline() { - return import('../../remote-timeline'); -} - -export function CommunityTimeline() { - return import('../../community-timeline'); -} - -export function HashtagTimeline() { - return import('../../hashtag-timeline'); -} - -export function DirectTimeline() { - return import('../../direct-timeline'); -} - -export function Conversations() { - return import('../../conversations'); -} - -export function ListTimeline() { - return import('../../list-timeline'); -} - -export function Lists() { - return import('../../lists'); -} - -export function Bookmarks() { - return import('../../bookmarks'); -} - -export function Status() { - return import('../../status'); -} - -export function PinnedStatuses() { - return import('../../pinned-statuses'); -} - -export function AccountTimeline() { - return import('../../account-timeline'); -} - -export function AccountGallery() { - return import('../../account-gallery'); -} - -export function Followers() { - return import('../../followers'); -} - -export function Following() { - return import('../../following'); -} - -export function FollowRequests() { - return import('../../follow-requests'); -} - -export function GenericNotFound() { - return import('../../generic-not-found'); -} - -export function FavouritedStatuses() { - return import('../../favourited-statuses'); -} - -export function Blocks() { - return import('../../blocks'); -} - -export function DomainBlocks() { - return import('../../domain-blocks'); -} - -export function Mutes() { - return import('../../mutes'); -} - -export function MuteModal() { - return import('../components/modals/mute-modal'); -} - -export function Filters() { - return import('../../filters'); -} - -export function EditFilter() { - return import('../../filters/edit-filter'); -} - -export function ReportModal() { - return import('../components/modals/report-modal/report-modal'); -} - -export function AccountModerationModal() { - return import('../components/modals/account-moderation-modal/account-moderation-modal'); -} - -export function MediaGallery() { - return import('../../../components/media-gallery'); -} - -export function Video() { - return import('../../video'); -} - -export function Audio() { - return import('../../audio'); -} - -export function MediaModal() { - return import('../components/modals/media-modal'); -} - -export function VideoModal() { - return import('../components/modals/video-modal'); -} - -export function BoostModal() { - return import('../components/modals/boost-modal'); -} - -export function ConfirmationModal() { - return import('../components/modals/confirmation-modal'); -} - -export function MissingDescriptionModal() { - return import('../components/modals/missing-description-modal'); -} - -export function ActionsModal() { - return import('../components/modals/actions-modal'); -} - -export function HotkeysModal() { - return import('../components/modals/hotkeys-modal'); -} - -export function ComposeModal() { - return import('../components/modals/compose-modal'); -} - -export function ReplyMentionsModal() { - return import('../components/modals/reply-mentions-modal'); -} - -export function UnauthorizedModal() { - return import('../components/modals/unauthorized-modal'); -} - -export function EditFederationModal() { - return import('../components/modals/edit-federation-modal'); -} - -export function EmbedModal() { - return import('../components/modals/embed-modal'); -} - -export function ComponentModal() { - return import('../components/modals/component-modal'); -} - -export function ReblogsModal() { - return import('../components/modals/reblogs-modal'); -} - -export function FavouritesModal() { - return import('../components/modals/favourites-modal'); -} - -export function DislikesModal() { - return import('../components/modals/dislikes-modal'); -} - -export function ReactionsModal() { - return import('../components/modals/reactions-modal'); -} - -export function MentionsModal() { - return import('../components/modals/mentions-modal'); -} - -export function LandingPageModal() { - return import('../components/modals/landing-page-modal'); -} - -export function BirthdaysModal() { - return import('../components/modals/birthdays-modal'); -} - -export function BirthdayPanel() { - return import('../../../components/birthday-panel'); -} - -export function ListEditor() { - return import('../../list-editor'); -} - -export function ListAdder() { - return import('../../list-adder'); -} - -export function Search() { - return import('../../search'); -} - -export function LoginPage() { - return import('../../auth-login/components/login-page'); -} - -export function ExternalLogin() { - return import('../../external-login'); -} - -export function LogoutPage() { - return import('../../auth-login/components/logout'); -} - -export function RegistrationPage() { - return import('../../auth-login/components/registration-page'); -} - -export function Settings() { - return import('../../settings'); -} - -export function EditProfile() { - return import('../../edit-profile'); -} - -export function EditEmail() { - return import('../../edit-email'); -} - -export function EmailConfirmation() { - return import('../../email-confirmation'); -} - -export function EditPassword() { - return import('../../edit-password'); -} - -export function DeleteAccount() { - return import('../../delete-account'); -} - -export function SoapboxConfig() { - return import('../../soapbox-config'); -} - -export function ExportData() { - return import('../../export-data'); -} - -export function ImportData() { - return import('../../import-data'); -} - -export function Backups() { - return import('../../backups'); -} - -export function PasswordReset() { - return import('../../auth-login/components/password-reset'); -} - -export function PasswordResetConfirm() { - return import('../../auth-login/components/password-reset-confirm'); -} - -export function MfaForm() { - return import('../../security/mfa-form'); -} - -export function ChatIndex() { - return import('../../chats'); -} - -export function ChatWidget() { - return import('../../chats/components/chat-widget/chat-widget'); -} - -export function ServerInfo() { - return import('../../server-info'); -} - -export function Dashboard() { - return import('../../admin'); -} - -export function ModerationLog() { - return import('../../admin/moderation-log'); -} - -export function ThemeEditor() { - return import('../../theme-editor'); -} - -export function UserPanel() { - return import('../components/user-panel'); -} - -export function PromoPanel() { - return import('../components/promo-panel'); -} - -export function SignUpPanel() { - return import('../components/panels/sign-up-panel'); -} - -export function CtaBanner() { - return import('../components/cta-banner'); -} - -export function FundingPanel() { - return import('../components/funding-panel'); -} - -export function TrendsPanel() { - return import('../components/trends-panel'); -} - -export function ProfileInfoPanel() { - return import('../components/profile-info-panel'); -} - -export function ProfileMediaPanel() { - return import('../components/profile-media-panel'); -} - -export function ProfileFieldsPanel() { - return import('../components/profile-fields-panel'); -} - -export function PinnedAccountsPanel() { - return import('../components/pinned-accounts-panel'); -} - -export function InstanceInfoPanel() { - return import('../components/instance-info-panel'); -} - -export function InstanceModerationPanel() { - return import('../components/instance-moderation-panel'); -} - -export function LatestAccountsPanel() { - return import('../../admin/components/latest-accounts-panel'); -} - -export function SidebarMenu() { - return import('../../../components/sidebar-menu'); -} - -export function ModalContainer() { - return import('../containers/modal-container'); -} - -export function ProfileHoverCard() { - return import('soapbox/components/profile-hover-card'); -} - -export function StatusHoverCard() { - return import('soapbox/components/status-hover-card'); -} - -export function CryptoDonate() { - return import('../../crypto-donate'); -} - -export function CryptoDonatePanel() { - return import('../../crypto-donate/components/crypto-donate-panel'); -} - -export function CryptoAddress() { - return import('../../crypto-donate/components/crypto-address'); -} - -export function CryptoDonateModal() { - return import('../components/modals/crypto-donate-modal'); -} - -export function ScheduledStatuses() { - return import('../../scheduled-statuses'); -} - -export function UserIndex() { - return import('../../admin/user-index'); -} - -export function FederationRestrictions() { - return import('../../federation-restrictions'); -} - -export function Aliases() { - return import('../../aliases'); -} - -export function Migration() { - return import('../../migration'); -} - -export function ScheduleForm() { - return import('../../compose/components/schedule-form'); -} - -export function WhoToFollowPanel() { - return import('../components/who-to-follow-panel'); -} - -export function FollowRecommendations() { - return import('../../follow-recommendations'); -} - -export function Directory() { - return import('../../directory'); -} - -export function RegisterInvite() { - return import('../../register-invite'); -} - -export function Share() { - return import('../../share'); -} - -export function NewStatus() { - return import('../../new-status'); -} - -export function IntentionalError() { - return import('../../intentional-error'); -} - -export function Developers() { - return import('../../developers'); -} - -export function CreateApp() { - return import('../../developers/apps/create'); -} - -export function SettingsStore() { - return import('../../developers/settings-store'); -} - -export function TestTimeline() { - return import('../../test-timeline'); -} - -export function ServiceWorkerInfo() { - return import('../../developers/service-worker-info'); -} - -export function DatePicker() { - return import('../../birthdays/date-picker'); -} - -export function OnboardingWizard() { - return import('../../onboarding/onboarding-wizard'); -} - -export function CompareHistoryModal() { - return import('../components/modals/compare-history-modal'); -} - -export function AuthTokenList() { - return import('../../auth-token-list'); -} - -export function FamiliarFollowersModal() { - return import('../components/modals/familiar-followers-modal'); -} - -export function AnnouncementsPanel() { - return import('../../../components/announcements/announcements-panel'); -} - -export function Quotes() { - return import('../../quotes'); -} - -export function ComposeEventModal() { - return import('../components/modals/compose-event-modal/compose-event-modal'); -} - -export function JoinEventModal() { - return import('../components/modals/join-event-modal'); -} - -export function EventHeader() { - return import('../../event/components/event-header'); -} - -export function EventInformation() { - return import('../../event/event-information'); -} - -export function EventDiscussion() { - return import('../../event/event-discussion'); -} - -export function EventMapModal() { - return import('../components/modals/event-map-modal'); -} - -export function EventParticipantsModal() { - return import('../components/modals/event-participants-modal'); -} - -export function Events() { - return import('../../events'); -} - -export function Groups() { - return import('../../groups'); -} - -export function GroupsDiscover() { - return import('../../groups/discover'); -} - -export function GroupsPopular() { - return import('../../groups/popular'); -} - -export function GroupsSuggested() { - return import('../../groups/suggested'); -} - -export function GroupsTag() { - return import('../../groups/tag'); -} - -export function GroupsTags() { - return import('../../groups/tags'); -} - -export function PendingGroupRequests() { - return import('../../groups/pending-requests'); -} - -export function GroupMembers() { - return import('../../group/group-members'); -} - -export function GroupTags() { - return import('../../group/group-tags'); -} - -export function GroupTagTimeline() { - return import('../../group/group-tag-timeline'); -} - -export function GroupTimeline() { - return import('../../group/group-timeline'); -} - -export function ManageGroup() { - return import('../../group/manage-group'); -} - -export function EditGroup() { - return import('../../group/edit-group'); -} - -export function GroupBlockedMembers() { - return import('../../group/group-blocked-members'); -} - -export function GroupMembershipRequests() { - return import('../../group/group-membership-requests'); -} - -export function GroupGallery() { - return import('../../group/group-gallery'); -} - -export function CreateGroupModal() { - return import('../components/modals/manage-group-modal/create-group-modal'); -} - -export function NewGroupPanel() { - return import('../components/panels/new-group-panel'); -} - -export function MyGroupsPanel() { - return import('../components/panels/my-groups-panel'); -} - -export function SuggestedGroupsPanel() { - return import('../components/panels/suggested-groups-panel'); -} - -export function GroupMediaPanel() { - return import('../components/group-media-panel'); -} - -export function NewEventPanel() { - return import('../components/panels/new-event-panel'); -} - -export function Announcements() { - return import('../../admin/announcements'); -} - -export function EditAnnouncementModal() { - return import('../components/modals/edit-announcement-modal'); -} - -export function FollowedTags() { - return import('../../followed-tags'); -} - -export function AccountNotePanel() { - return import('../components/panels/account-note-panel'); -} - -export function ComposeEditor() { - return import('../../compose/editor'); -} +import { lazy } from 'react'; + +export const AboutPage = lazy(() => import('soapbox/features/about')); +export const EmojiPicker = lazy(() => import('soapbox/features/emoji/components/emoji-picker')); +export const Notifications = lazy(() => import('soapbox/features/notifications')); +export const LandingTimeline = lazy(() => import('soapbox/features/landing-timeline')); +export const HomeTimeline = lazy(() => import('soapbox/features/home-timeline')); +export const PublicTimeline = lazy(() => import('soapbox/features/public-timeline')); +export const RemoteTimeline = lazy(() => import('soapbox/features/remote-timeline')); +export const CommunityTimeline = lazy(() => import('soapbox/features/community-timeline')); +export const HashtagTimeline = lazy(() => import('soapbox/features/hashtag-timeline')); +export const DirectTimeline = lazy(() => import('soapbox/features/direct-timeline')); +export const Conversations = lazy(() => import('soapbox/features/conversations')); +export const ListTimeline = lazy(() => import('soapbox/features/list-timeline')); +export const Lists = lazy(() => import('soapbox/features/lists')); +export const Bookmarks = lazy(() => import('soapbox/features/bookmarks')); +export const Status = lazy(() => import('soapbox/features/status')); +export const PinnedStatuses = lazy(() => import('soapbox/features/pinned-statuses')); +export const AccountTimeline = lazy(() => import('soapbox/features/account-timeline')); +export const AccountGallery = lazy(() => import('soapbox/features/account-gallery')); +export const Followers = lazy(() => import('soapbox/features/followers')); +export const Following = lazy(() => import('soapbox/features/following')); +export const FollowRequests = lazy(() => import('soapbox/features/follow-requests')); +export const GenericNotFound = lazy(() => import('soapbox/features/generic-not-found')); +export const FavouritedStatuses = lazy(() => import('soapbox/features/favourited-statuses')); +export const Blocks = lazy(() => import('soapbox/features/blocks')); +export const DomainBlocks = lazy(() => import('soapbox/features/domain-blocks')); +export const Mutes = lazy(() => import('soapbox/features/mutes')); +export const MuteModal = lazy(() => import('soapbox/features/ui/components/modals/mute-modal')); +export const Filters = lazy(() => import('soapbox/features/filters')); +export const EditFilter = lazy(() => import('soapbox/features/filters/edit-filter')); +export const ReportModal = lazy(() => import('soapbox/features/ui/components/modals/report-modal/report-modal')); +export const AccountModerationModal = lazy(() => import('soapbox/features/ui/components/modals/account-moderation-modal/account-moderation-modal')); +export const MediaGallery = lazy(() => import('soapbox/components/media-gallery')); +export const Video = lazy(() => import('soapbox/features/video')); +export const Audio = lazy(() => import('soapbox/features/audio')); +export const MediaModal = lazy(() => import('soapbox/features/ui/components/modals/media-modal')); +export const VideoModal = lazy(() => import('soapbox/features/ui/components/modals/video-modal')); +export const BoostModal = lazy(() => import('soapbox/features/ui/components/modals/boost-modal')); +export const ConfirmationModal = lazy(() => import('soapbox/features/ui/components/modals/confirmation-modal')); +export const MissingDescriptionModal = lazy(() => import('soapbox/features/ui/components/modals/missing-description-modal')); +export const ActionsModal = lazy(() => import('soapbox/features/ui/components/modals/actions-modal')); +export const HotkeysModal = lazy(() => import('soapbox/features/ui/components/modals/hotkeys-modal')); +export const ComposeModal = lazy(() => import('soapbox/features/ui/components/modals/compose-modal')); +export const ReplyMentionsModal = lazy(() => import('soapbox/features/ui/components/modals/reply-mentions-modal')); +export const UnauthorizedModal = lazy(() => import('soapbox/features/ui/components/modals/unauthorized-modal')); +export const EditFederationModal = lazy(() => import('soapbox/features/ui/components/modals/edit-federation-modal')); +export const EmbedModal = lazy(() => import('soapbox/features/ui/components/modals/embed-modal')); +export const ComponentModal = lazy(() => import('soapbox/features/ui/components/modals/component-modal')); +export const ReblogsModal = lazy(() => import('soapbox/features/ui/components/modals/reblogs-modal')); +export const FavouritesModal = lazy(() => import('soapbox/features/ui/components/modals/favourites-modal')); +export const DislikesModal = lazy(() => import('soapbox/features/ui/components/modals/dislikes-modal')); +export const ReactionsModal = lazy(() => import('soapbox/features/ui/components/modals/reactions-modal')); +export const MentionsModal = lazy(() => import('soapbox/features/ui/components/modals/mentions-modal')); +export const LandingPageModal = lazy(() => import('soapbox/features/ui/components/modals/landing-page-modal')); +export const BirthdaysModal = lazy(() => import('soapbox/features/ui/components/modals/birthdays-modal')); +export const BirthdayPanel = lazy(() => import('soapbox/components/birthday-panel')); +export const ListEditor = lazy(() => import('soapbox/features/list-editor')); +export const ListAdder = lazy(() => import('soapbox/features/list-adder')); +export const Search = lazy(() => import('soapbox/features/search')); +export const LoginPage = lazy(() => import('soapbox/features/auth-login/components/login-page')); +export const ExternalLogin = lazy(() => import('soapbox/features/external-login')); +export const LogoutPage = lazy(() => import('soapbox/features/auth-login/components/logout')); +export const RegistrationPage = lazy(() => import('soapbox/features/auth-login/components/registration-page')); +export const Settings = lazy(() => import('soapbox/features/settings')); +export const EditProfile = lazy(() => import('soapbox/features/edit-profile')); +export const EditEmail = lazy(() => import('soapbox/features/edit-email')); +export const EmailConfirmation = lazy(() => import('soapbox/features/email-confirmation')); +export const EditPassword = lazy(() => import('soapbox/features/edit-password')); +export const DeleteAccount = lazy(() => import('soapbox/features/delete-account')); +export const SoapboxConfig = lazy(() => import('soapbox/features/soapbox-config')); +export const ExportData = lazy(() => import('soapbox/features/export-data')); +export const ImportData = lazy(() => import('soapbox/features/import-data')); +export const Backups = lazy(() => import('soapbox/features/backups')); +export const PasswordReset = lazy(() => import('soapbox/features/auth-login/components/password-reset')); +export const PasswordResetConfirm = lazy(() => import('soapbox/features/auth-login/components/password-reset-confirm')); +export const MfaForm = lazy(() => import('soapbox/features/security/mfa-form')); +export const ChatIndex = lazy(() => import('soapbox/features/chats')); +export const ChatWidget = lazy(() => import('soapbox/features/chats/components/chat-widget/chat-widget')); +export const ServerInfo = lazy(() => import('soapbox/features/server-info')); +export const Dashboard = lazy(() => import('soapbox/features/admin')); +export const ModerationLog = lazy(() => import('soapbox/features/admin/moderation-log')); +export const ThemeEditor = lazy(() => import('soapbox/features/theme-editor')); +export const UserPanel = lazy(() => import('soapbox/features/ui/components/user-panel')); +export const PromoPanel = lazy(() => import('soapbox/features/ui/components/promo-panel')); +export const SignUpPanel = lazy(() => import('soapbox/features/ui/components/panels/sign-up-panel')); +export const CtaBanner = lazy(() => import('soapbox/features/ui/components/cta-banner')); +export const FundingPanel = lazy(() => import('soapbox/features/ui/components/funding-panel')); +export const TrendsPanel = lazy(() => import('soapbox/features/ui/components/trends-panel')); +export const ProfileInfoPanel = lazy(() => import('soapbox/features/ui/components/profile-info-panel')); +export const ProfileMediaPanel = lazy(() => import('soapbox/features/ui/components/profile-media-panel')); +export const ProfileFieldsPanel = lazy(() => import('soapbox/features/ui/components/profile-fields-panel')); +export const PinnedAccountsPanel = lazy(() => import('soapbox/features/ui/components/pinned-accounts-panel')); +export const InstanceInfoPanel = lazy(() => import('soapbox/features/ui/components/instance-info-panel')); +export const InstanceModerationPanel = lazy(() => import('soapbox/features/ui/components/instance-moderation-panel')); +export const LatestAccountsPanel = lazy(() => import('soapbox/features/admin/components/latest-accounts-panel')); +export const SidebarMenu = lazy(() => import('soapbox/components/sidebar-menu')); +export const ModalContainer = lazy(() => import('soapbox/features/ui/containers/modal-container')); +export const ProfileHoverCard = lazy(() => import('soapbox/components/profile-hover-card')); +export const StatusHoverCard = lazy(() => import('soapbox/components/status-hover-card')); +export const CryptoDonate = lazy(() => import('soapbox/features/crypto-donate')); +export const CryptoDonatePanel = lazy(() => import('soapbox/features/crypto-donate/components/crypto-donate-panel')); +export const CryptoAddress = lazy(() => import('soapbox/features/crypto-donate/components/crypto-address')); +export const CryptoDonateModal = lazy(() => import('soapbox/features/ui/components/modals/crypto-donate-modal')); +export const ScheduledStatuses = lazy(() => import('soapbox/features/scheduled-statuses')); +export const UserIndex = lazy(() => import('soapbox/features/admin/user-index')); +export const FederationRestrictions = lazy(() => import('soapbox/features/federation-restrictions')); +export const Aliases = lazy(() => import('soapbox/features/aliases')); +export const Migration = lazy(() => import('soapbox/features/migration')); +export const ScheduleForm = lazy(() => import('soapbox/features/compose/components/schedule-form')); +export const WhoToFollowPanel = lazy(() => import('soapbox/features/ui/components/who-to-follow-panel')); +export const FollowRecommendations = lazy(() => import('soapbox/features/follow-recommendations')); +export const Directory = lazy(() => import('soapbox/features/directory')); +export const RegisterInvite = lazy(() => import('soapbox/features/register-invite')); +export const Share = lazy(() => import('soapbox/features/share')); +export const NewStatus = lazy(() => import('soapbox/features/new-status')); +export const IntentionalError = lazy(() => import('soapbox/features/intentional-error')); +export const Developers = lazy(() => import('soapbox/features/developers')); +export const CreateApp = lazy(() => import('soapbox/features/developers/apps/create')); +export const SettingsStore = lazy(() => import('soapbox/features/developers/settings-store')); +export const TestTimeline = lazy(() => import('soapbox/features/test-timeline')); +export const ServiceWorkerInfo = lazy(() => import('soapbox/features/developers/service-worker-info')); +export const DatePicker = lazy(() => import('soapbox/features/birthdays/date-picker')); +export const OnboardingWizard = lazy(() => import('soapbox/features/onboarding/onboarding-wizard')); +export const CompareHistoryModal = lazy(() => import('soapbox/features/ui/components/modals/compare-history-modal')); +export const AuthTokenList = lazy(() => import('soapbox/features/auth-token-list')); +export const FamiliarFollowersModal = lazy(() => import('soapbox/features/ui/components/modals/familiar-followers-modal')); +export const AnnouncementsPanel = lazy(() => import('soapbox/components/announcements/announcements-panel')); +export const Quotes = lazy(() => import('soapbox/features/quotes')); +export const ComposeEventModal = lazy(() => import('soapbox/features/ui/components/modals/compose-event-modal/compose-event-modal')); +export const JoinEventModal = lazy(() => import('soapbox/features/ui/components/modals/join-event-modal')); +export const EventHeader = lazy(() => import('soapbox/features/event/components/event-header')); +export const EventInformation = lazy(() => import('soapbox/features/event/event-information')); +export const EventDiscussion = lazy(() => import('soapbox/features/event/event-discussion')); +export const EventMapModal = lazy(() => import('soapbox/features/ui/components/modals/event-map-modal')); +export const EventParticipantsModal = lazy(() => import('soapbox/features/ui/components/modals/event-participants-modal')); +export const Events = lazy(() => import('soapbox/features/events')); +export const Groups = lazy(() => import('soapbox/features/groups')); +export const GroupsDiscover = lazy(() => import('soapbox/features/groups/discover')); +export const GroupsPopular = lazy(() => import('soapbox/features/groups/popular')); +export const GroupsSuggested = lazy(() => import('soapbox/features/groups/suggested')); +export const GroupsTag = lazy(() => import('soapbox/features/groups/tag')); +export const GroupsTags = lazy(() => import('soapbox/features/groups/tags')); +export const PendingGroupRequests = lazy(() => import('soapbox/features/groups/pending-requests')); +export const GroupMembers = lazy(() => import('soapbox/features/group/group-members')); +export const GroupTags = lazy(() => import('soapbox/features/group/group-tags')); +export const GroupTagTimeline = lazy(() => import('soapbox/features/group/group-tag-timeline')); +export const GroupTimeline = lazy(() => import('soapbox/features/group/group-timeline')); +export const ManageGroup = lazy(() => import('soapbox/features/group/manage-group')); +export const EditGroup = lazy(() => import('soapbox/features/group/edit-group')); +export const GroupBlockedMembers = lazy(() => import('soapbox/features/group/group-blocked-members')); +export const GroupMembershipRequests = lazy(() => import('soapbox/features/group/group-membership-requests')); +export const GroupGallery = lazy(() => import('soapbox/features/group/group-gallery')); +export const CreateGroupModal = lazy(() => import('soapbox/features/ui/components/modals/manage-group-modal/create-group-modal')); +export const NewGroupPanel = lazy(() => import('soapbox/features/ui/components/panels/new-group-panel')); +export const MyGroupsPanel = lazy(() => import('soapbox/features/ui/components/panels/my-groups-panel')); +export const SuggestedGroupsPanel = lazy(() => import('soapbox/features/ui/components/panels/suggested-groups-panel')); +export const GroupMediaPanel = lazy(() => import('soapbox/features/ui/components/group-media-panel')); +export const NewEventPanel = lazy(() => import('soapbox/features/ui/components/panels/new-event-panel')); +export const Announcements = lazy(() => import('soapbox/features/admin/announcements')); +export const EditAnnouncementModal = lazy(() => import('soapbox/features/ui/components/modals/edit-announcement-modal')); +export const FollowedTags = lazy(() => import('soapbox/features/followed-tags')); +export const AccountNotePanel = lazy(() => import('soapbox/features/ui/components/panels/account-note-panel')); +export const ComposeEditor = lazy(() => import('soapbox/features/compose/editor')); From 3a221e8c86ca5f749b18ef0633960a12eb6e9d4d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 15:37:36 -0500 Subject: [PATCH 2/7] Bundle: just wrap it with React.Suspense --- .../components/emoji-picker-dropdown.tsx | 50 +++----- src/features/ui/components/bundle.tsx | 121 +++--------------- .../ui/containers/bundle-container.tsx | 20 +-- src/features/ui/index.tsx | 4 +- src/features/ui/util/react-router-helpers.tsx | 2 +- 5 files changed, 35 insertions(+), 162 deletions(-) diff --git a/src/features/emoji/components/emoji-picker-dropdown.tsx b/src/features/emoji/components/emoji-picker-dropdown.tsx index 379ae9c5b..8917272b3 100644 --- a/src/features/emoji/components/emoji-picker-dropdown.tsx +++ b/src/features/emoji/components/emoji-picker-dropdown.tsx @@ -9,12 +9,10 @@ import { useAppDispatch, useAppSelector, useTheme } from 'soapbox/hooks'; import { RootState } from 'soapbox/store'; import { buildCustomEmojis } from '../../emoji'; -import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components'; +import { EmojiPicker } from '../../ui/util/async-components'; import type { Emoji, CustomEmoji, NativeEmoji } from 'soapbox/features/emoji'; -let EmojiPicker: any; // load asynchronously - export const messages = defineMessages({ emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, emoji_pick: { id: 'emoji_button.pick', defaultMessage: 'Pick an emoji…' }, @@ -136,8 +134,6 @@ const EmojiPickerDropdown: React.FC = ({ const customEmojis = useAppSelector((state) => getCustomEmojis(state)); const frequentlyUsedEmojis = useAppSelector((state) => getFrequentlyUsedEmojis(state)); - const [loading, setLoading] = useState(false); - const handlePick = (emoji: any) => { setVisible(false); @@ -210,18 +206,6 @@ const EmojiPickerDropdown: React.FC = ({ } else { document.body.style.overflow = ''; } - - if (!EmojiPicker) { - setLoading(true); - - EmojiPickerAsync().then(EmojiMart => { - EmojiPicker = EmojiMart.Picker; - - setLoading(false); - }).catch(() => { - setLoading(false); - }); - } }, [visible]); useEffect(() => () => { @@ -231,23 +215,21 @@ const EmojiPickerDropdown: React.FC = ({ return ( visible ? ( - {!loading && ( - - )} + ) : null ); diff --git a/src/features/ui/components/bundle.tsx b/src/features/ui/components/bundle.tsx index 58157901d..dc84acf69 100644 --- a/src/features/ui/components/bundle.tsx +++ b/src/features/ui/components/bundle.tsx @@ -1,114 +1,23 @@ -import React from 'react'; +import React, { Suspense } from 'react'; -const emptyComponent = () => null; -const noop = () => { }; - -export interface BundleProps { - fetchComponent: () => Promise; - loading: React.ComponentType; - error: React.ComponentType<{ onRetry: (props?: BundleProps) => void }>; - children: (mod: any) => React.ReactNode; +export interface IBundle> { + fetchComponent: React.LazyExoticComponent; + loading?: React.ComponentType; + error?: React.ComponentType<{ onRetry: (props?: IBundle) => void }>; + children: (component: React.LazyExoticComponent) => React.ReactNode; renderDelay?: number; - onFetch: () => void; - onFetchSuccess: () => void; - onFetchFail: (error: any) => void; -} - -interface BundleState { - mod: any; - forceRender: boolean; + onFetch?: () => void; + onFetchSuccess?: () => void; + onFetchFail?: (error: any) => void; } /** Fetches and renders an async component. */ -class Bundle extends React.PureComponent { - - timeout: NodeJS.Timeout | undefined; - timestamp: Date | undefined; - - static defaultProps = { - loading: emptyComponent, - error: emptyComponent, - renderDelay: 0, - onFetch: noop, - onFetchSuccess: noop, - onFetchFail: noop, - }; - - static cache = new Map; - - state = { - mod: undefined, - forceRender: false, - }; - - componentDidMount() { - this.load(this.props); - } - - UNSAFE_componentWillReceiveProps(nextProps: BundleProps) { - if (nextProps.fetchComponent !== this.props.fetchComponent) { - this.load(nextProps); - } - } - - componentWillUnmount() { - if (this.timeout) { - clearTimeout(this.timeout); - } - } - - load = (props?: BundleProps) => { - const { fetchComponent, onFetch, onFetchSuccess, onFetchFail, renderDelay } = props || this.props; - const cachedMod = Bundle.cache.get(fetchComponent); - - if (fetchComponent === undefined) { - this.setState({ mod: null }); - return Promise.resolve(); - } - - onFetch(); - - if (cachedMod) { - this.setState({ mod: cachedMod.default }); - onFetchSuccess(); - return Promise.resolve(); - } - - this.setState({ mod: undefined }); - - if (renderDelay !== 0) { - this.timestamp = new Date(); - this.timeout = setTimeout(() => this.setState({ forceRender: true }), renderDelay); - } - - return fetchComponent() - .then((mod) => { - Bundle.cache.set(fetchComponent, mod); - this.setState({ mod: mod.default }); - onFetchSuccess(); - }) - .catch((error) => { - this.setState({ mod: null }); - onFetchFail(error); - }); - }; - - render() { - const { loading: Loading, error: Error, children, renderDelay } = this.props; - const { mod, forceRender } = this.state; - const elapsed = this.timestamp ? ((new Date()).getTime() - this.timestamp.getTime()) : renderDelay!; - - if (mod === undefined) { - return (elapsed >= renderDelay! || forceRender) ? : null; - } - - if (mod === null) { - return ; - } - - return children(mod); - } - +function Bundle>({ fetchComponent, loading: Loading, children }: IBundle) { + return ( + : null}> + {children(fetchComponent)} + + ); } export default Bundle; diff --git a/src/features/ui/containers/bundle-container.tsx b/src/features/ui/containers/bundle-container.tsx index 50a8b8629..b94b1bb02 100644 --- a/src/features/ui/containers/bundle-container.tsx +++ b/src/features/ui/containers/bundle-container.tsx @@ -1,21 +1,3 @@ -import { connect } from 'react-redux'; - -import { fetchBundleRequest, fetchBundleSuccess, fetchBundleFail } from 'soapbox/actions/bundles'; - import Bundle from '../components/bundle'; -import type { AppDispatch } from 'soapbox/store'; - -const mapDispatchToProps = (dispatch: AppDispatch) => ({ - onFetch() { - dispatch(fetchBundleRequest()); - }, - onFetchSuccess() { - dispatch(fetchBundleSuccess()); - }, - onFetchFail(error: any) { - dispatch(fetchBundleFail(error)); - }, -}); - -export default connect(null, mapDispatchToProps)(Bundle); +export default Bundle; diff --git a/src/features/ui/index.tsx b/src/features/ui/index.tsx index 0e1f30a08..cbc8590b5 100644 --- a/src/features/ui/index.tsx +++ b/src/features/ui/index.tsx @@ -1,5 +1,5 @@ import clsx from 'clsx'; -import React, { useEffect, useRef } from 'react'; +import React, { lazy, useEffect, useRef } from 'react'; import { Switch, useHistory, useLocation, Redirect } from 'react-router-dom'; import { fetchFollowRequests } from 'soapbox/actions/accounts'; @@ -354,7 +354,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => - new Promise((_resolve, reject) => reject())} content={children} /> + Promise.reject())} content={children} /> {hasCrypto && } diff --git a/src/features/ui/util/react-router-helpers.tsx b/src/features/ui/util/react-router-helpers.tsx index 911e3b430..02a5fb180 100644 --- a/src/features/ui/util/react-router-helpers.tsx +++ b/src/features/ui/util/react-router-helpers.tsx @@ -17,7 +17,7 @@ type PageProps = { }; interface IWrappedRoute extends RouteProps { - component: (...args: any[]) => any; + component: React.LazyExoticComponent; page?: React.ComponentType; content?: React.ReactNode; componentParams?: Record; From 5b539416d91af1e2e75b1be64ef0bf36b766e74a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 15:38:15 -0500 Subject: [PATCH 3/7] ProfileHoverCard/StatusHoverCard: make `visible` an optional prop --- src/components/profile-hover-card.tsx | 2 +- src/components/status-hover-card.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/profile-hover-card.tsx b/src/components/profile-hover-card.tsx index f7517430e..ddb89e11e 100644 --- a/src/components/profile-hover-card.tsx +++ b/src/components/profile-hover-card.tsx @@ -56,7 +56,7 @@ const handleMouseLeave = (dispatch: AppDispatch): React.MouseEventHandler => { }; interface IProfileHoverCard { - visible: boolean; + visible?: boolean; } /** Popup profile preview that appears when hovering avatars and display names. */ diff --git a/src/components/status-hover-card.tsx b/src/components/status-hover-card.tsx index 5c31f9b4d..08359c61a 100644 --- a/src/components/status-hover-card.tsx +++ b/src/components/status-hover-card.tsx @@ -15,7 +15,7 @@ import { showStatusHoverCard } from './hover-status-wrapper'; import { Card, CardBody } from './ui'; interface IStatusHoverCard { - visible: boolean; + visible?: boolean; } /** Popup status preview that appears when hovering reply to */ From 0f10922c3d156f397d471cebb93fdba6730038c6 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 15:43:34 -0500 Subject: [PATCH 4/7] ProfilePage: fix types of async components --- src/features/ui/components/panels/account-note-panel.tsx | 2 +- src/features/ui/components/pinned-accounts-panel.tsx | 2 +- src/features/ui/components/profile-familiar-followers.tsx | 2 +- src/features/ui/components/profile-fields-panel.tsx | 2 +- src/features/ui/components/profile-info-panel.tsx | 2 +- src/features/ui/components/profile-media-panel.tsx | 3 ++- src/pages/remote-instance-page.tsx | 6 +++--- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/features/ui/components/panels/account-note-panel.tsx b/src/features/ui/components/panels/account-note-panel.tsx index 045fd6083..032039dae 100644 --- a/src/features/ui/components/panels/account-note-panel.tsx +++ b/src/features/ui/components/panels/account-note-panel.tsx @@ -7,8 +7,8 @@ import { submitAccountNote } from 'soapbox/actions/account-notes'; import { HStack, Text, Widget } from 'soapbox/components/ui'; import { useAppDispatch } from 'soapbox/hooks'; +import type { Account as AccountEntity } from 'soapbox/schemas'; import type { AppDispatch } from 'soapbox/store'; -import type { Account as AccountEntity } from 'soapbox/types/entities'; const onSave = debounce( (dispatch: AppDispatch, id: string, value: string, callback: () => void) => diff --git a/src/features/ui/components/pinned-accounts-panel.tsx b/src/features/ui/components/pinned-accounts-panel.tsx index d9aed232b..b0f5e918f 100644 --- a/src/features/ui/components/pinned-accounts-panel.tsx +++ b/src/features/ui/components/pinned-accounts-panel.tsx @@ -9,7 +9,7 @@ import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import { WhoToFollowPanel } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import type { Account } from 'soapbox/types/entities'; +import type { Account } from 'soapbox/schemas'; interface IPinnedAccountsPanel { account: Account; diff --git a/src/features/ui/components/profile-familiar-followers.tsx b/src/features/ui/components/profile-familiar-followers.tsx index 749e52f93..c80e46b04 100644 --- a/src/features/ui/components/profile-familiar-followers.tsx +++ b/src/features/ui/components/profile-familiar-followers.tsx @@ -12,7 +12,7 @@ import VerificationBadge from 'soapbox/components/verification-badge'; import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; import { makeGetAccount } from 'soapbox/selectors'; -import type { Account } from 'soapbox/types/entities'; +import type { Account } from 'soapbox/schemas'; const getAccount = makeGetAccount(); diff --git a/src/features/ui/components/profile-fields-panel.tsx b/src/features/ui/components/profile-fields-panel.tsx index 946cf35a7..fb434a25b 100644 --- a/src/features/ui/components/profile-fields-panel.tsx +++ b/src/features/ui/components/profile-fields-panel.tsx @@ -5,7 +5,7 @@ import { Widget, Stack } from 'soapbox/components/ui'; import ProfileField from './profile-field'; -import type { Account } from 'soapbox/types/entities'; +import type { Account } from 'soapbox/schemas'; interface IProfileFieldsPanel { account: Account; diff --git a/src/features/ui/components/profile-info-panel.tsx b/src/features/ui/components/profile-info-panel.tsx index d44a83d8e..244434b8b 100644 --- a/src/features/ui/components/profile-info-panel.tsx +++ b/src/features/ui/components/profile-info-panel.tsx @@ -15,7 +15,7 @@ import ProfileFamiliarFollowers from './profile-familiar-followers'; import ProfileField from './profile-field'; import ProfileStats from './profile-stats'; -import type { Account } from 'soapbox/types/entities'; +import type { Account } from 'soapbox/schemas'; /** Basically ensure the URL isn't `javascript:alert('hi')` or something like that */ const isSafeUrl = (text: string): boolean => { diff --git a/src/features/ui/components/profile-media-panel.tsx b/src/features/ui/components/profile-media-panel.tsx index f87b12c55..d63b849f3 100644 --- a/src/features/ui/components/profile-media-panel.tsx +++ b/src/features/ui/components/profile-media-panel.tsx @@ -10,7 +10,8 @@ import { getAccountGallery } from 'soapbox/selectors'; import MediaItem from '../../account-gallery/components/media-item'; -import type { Account, Attachment } from 'soapbox/types/entities'; +import type { Account } from 'soapbox/schemas'; +import type { Attachment } from 'soapbox/types/entities'; interface IProfileMediaPanel { account?: Account; diff --git a/src/pages/remote-instance-page.tsx b/src/pages/remote-instance-page.tsx index b5c4e5262..60a61e16d 100644 --- a/src/pages/remote-instance-page.tsx +++ b/src/pages/remote-instance-page.tsx @@ -13,15 +13,15 @@ import { federationRestrictionsDisclosed } from 'soapbox/utils/state'; import { Layout } from '../components/ui'; interface IRemoteInstancePage { - params?: { - instance?: string; + params: { + instance: string; }; children: React.ReactNode; } /** Page for viewing a remote instance timeline. */ const RemoteInstancePage: React.FC = ({ children, params }) => { - const host = params?.instance; + const host = params.instance; const { account } = useOwnAccount(); const disclosed = useAppSelector(federationRestrictionsDisclosed); From 1b213452b7a8f1c060cba84d26bd91268c6e350c Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 16:00:42 -0500 Subject: [PATCH 5/7] Fix Bundle type errors, remove bundle error components, remove group slug support --- src/components/hoc/group-lookup-hoc.tsx | 62 ------------------- src/components/hoc/with-hoc.tsx | 11 ---- .../ui/components/bundle-column-error.tsx | 39 ------------ .../ui/components/bundle-modal-error.tsx | 35 ----------- src/features/ui/components/modal-root.tsx | 10 +-- src/features/ui/index.tsx | 24 ------- src/features/ui/util/react-router-helpers.tsx | 6 +- src/pages/event-page.tsx | 2 +- src/pages/group-page.tsx | 3 +- src/pages/remote-instance-page.tsx | 6 +- 10 files changed, 9 insertions(+), 189 deletions(-) delete mode 100644 src/components/hoc/group-lookup-hoc.tsx delete mode 100644 src/components/hoc/with-hoc.tsx delete mode 100644 src/features/ui/components/bundle-column-error.tsx delete mode 100644 src/features/ui/components/bundle-modal-error.tsx diff --git a/src/components/hoc/group-lookup-hoc.tsx b/src/components/hoc/group-lookup-hoc.tsx deleted file mode 100644 index 570ec2e69..000000000 --- a/src/components/hoc/group-lookup-hoc.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; - -import { useGroupLookup } from 'soapbox/api/hooks'; -import ColumnLoading from 'soapbox/features/ui/components/column-loading'; - -import { Layout } from '../ui'; - -interface IGroupLookup { - params: { - groupSlug: string; - }; -} - -interface IMaybeGroupLookup { - params?: { - groupSlug?: string; - groupId?: string; - }; -} - -function GroupLookupHoc(Component: React.ComponentType<{ params: { groupId: string } }>) { - const GroupLookup: React.FC = (props) => { - const { entity: group } = useGroupLookup(props.params.groupSlug); - - if (!group) return ( - <> - - - - - - - ); - - const newProps = { - ...props, - params: { - ...props.params, - id: group.id, - groupId: group.id, - }, - }; - - return ( - - ); - }; - - const MaybeGroupLookup: React.FC = (props) => { - const { params } = props; - - if (params?.groupId) { - return ; - } else { - return ; - } - }; - - return MaybeGroupLookup; -} - -export default GroupLookupHoc; \ No newline at end of file diff --git a/src/components/hoc/with-hoc.tsx b/src/components/hoc/with-hoc.tsx deleted file mode 100644 index d5752a45f..000000000 --- a/src/components/hoc/with-hoc.tsx +++ /dev/null @@ -1,11 +0,0 @@ -type HOC = (Component: React.ComponentType

) => React.ComponentType -type AsyncComponent

= () => Promise<{ default: React.ComponentType

}> - -const withHoc = (asyncComponent: AsyncComponent

, hoc: HOC) => { - return async () => { - const { default: component } = await asyncComponent(); - return { default: hoc(component) }; - }; -}; - -export default withHoc; \ No newline at end of file diff --git a/src/features/ui/components/bundle-column-error.tsx b/src/features/ui/components/bundle-column-error.tsx deleted file mode 100644 index 4653610da..000000000 --- a/src/features/ui/components/bundle-column-error.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import { defineMessages, useIntl } from 'react-intl'; - -import { Column, Stack, Text, IconButton } from 'soapbox/components/ui'; - -const messages = defineMessages({ - title: { id: 'bundle_column_error.title', defaultMessage: 'Network error' }, - body: { id: 'bundle_column_error.body', defaultMessage: 'Something went wrong while loading this page.' }, - retry: { id: 'bundle_column_error.retry', defaultMessage: 'Try again' }, -}); - -interface IBundleColumnError { - onRetry: () => void; -} - -const BundleColumnError: React.FC = ({ onRetry }) => { - const intl = useIntl(); - - const handleRetry = () => { - onRetry(); - }; - - return ( - - - - - {intl.formatMessage(messages.body)} - - - ); -}; - -export default BundleColumnError; diff --git a/src/features/ui/components/bundle-modal-error.tsx b/src/features/ui/components/bundle-modal-error.tsx deleted file mode 100644 index 1b33d3d22..000000000 --- a/src/features/ui/components/bundle-modal-error.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import { defineMessages, useIntl } from 'react-intl'; - -import { Modal } from 'soapbox/components/ui'; - -const messages = defineMessages({ - error: { id: 'bundle_modal_error.message', defaultMessage: 'Something went wrong while loading this modal.' }, - retry: { id: 'bundle_modal_error.retry', defaultMessage: 'Try again' }, - close: { id: 'bundle_modal_error.close', defaultMessage: 'Close' }, -}); - -interface IBundleModalError { - onRetry: () => void; - onClose: () => void; -} - -const BundleModalError: React.FC = ({ onRetry, onClose }) => { - const intl = useIntl(); - - const handleRetry = () => { - onRetry(); - }; - - return ( - - ); -}; - -export default BundleModalError; diff --git a/src/features/ui/components/modal-root.tsx b/src/features/ui/components/modal-root.tsx index b4097d220..5dc8bd6ca 100644 --- a/src/features/ui/components/modal-root.tsx +++ b/src/features/ui/components/modal-root.tsx @@ -40,12 +40,10 @@ import { import BundleContainer from '../containers/bundle-container'; -import { BundleProps } from './bundle'; -import BundleModalError from './bundle-modal-error'; import ModalLoading from './modal-loading'; /* eslint sort-keys: "error" */ -const MODAL_COMPONENTS = { +const MODAL_COMPONENTS: Record> = { 'ACCOUNT_MODERATION': AccountModerationModal, 'ACTIONS': ActionsModal, 'BIRTHDAYS': BirthdaysModal, @@ -108,10 +106,6 @@ export default class ModalRoot extends React.PureComponent { return !['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].includes(modalId) ? : null; }; - renderError: React.ComponentType<{ onRetry: (props?: BundleProps) => void }> = (props) => { - return ; - }; - onClickClose = (_?: ModalType) => { const { onClose, type } = this.props; onClose(type); @@ -124,7 +118,7 @@ export default class ModalRoot extends React.PureComponent { return ( {visible && ( - + {(SpecificComponent) => } )} diff --git a/src/features/ui/index.tsx b/src/features/ui/index.tsx index cbc8590b5..39db6599b 100644 --- a/src/features/ui/index.tsx +++ b/src/features/ui/index.tsx @@ -15,8 +15,6 @@ import { fetchSuggestionsForTimeline } from 'soapbox/actions/suggestions'; import { expandHomeTimeline } from 'soapbox/actions/timelines'; import { useUserStream } from 'soapbox/api/hooks'; import { useSignerStream } from 'soapbox/api/hooks/nostr/useSignerStream'; -import GroupLookupHoc from 'soapbox/components/hoc/group-lookup-hoc'; -import withHoc from 'soapbox/components/hoc/with-hoc'; import SidebarNavigation from 'soapbox/components/sidebar-navigation'; import ThumbNavigation from 'soapbox/components/thumb-navigation'; import { Layout } from 'soapbox/components/ui'; @@ -147,16 +145,6 @@ import { WrappedRoute } from './util/react-router-helpers'; // Without this it ends up in ~8 very commonly used bundles. import 'soapbox/components/status'; -const GroupTagsSlug = withHoc(GroupTags as any, GroupLookupHoc); -const GroupTagTimelineSlug = withHoc(GroupTagTimeline as any, GroupLookupHoc); -const GroupTimelineSlug = withHoc(GroupTimeline as any, GroupLookupHoc); -const GroupMembersSlug = withHoc(GroupMembers as any, GroupLookupHoc); -const GroupGallerySlug = withHoc(GroupGallery as any, GroupLookupHoc); -const ManageGroupSlug = withHoc(ManageGroup as any, GroupLookupHoc); -const EditGroupSlug = withHoc(EditGroup as any, GroupLookupHoc); -const GroupBlockedMembersSlug = withHoc(GroupBlockedMembers as any, GroupLookupHoc); -const GroupMembershipRequestsSlug = withHoc(GroupMembershipRequests as any, GroupLookupHoc); - interface ISwitchingColumnsArea { children: React.ReactNode; } @@ -310,18 +298,6 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {features.groups && } {features.groups && } - {features.groupsTags && } - {features.groupsTags && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.groups && } - {features.scheduledStatuses && } diff --git a/src/features/ui/util/react-router-helpers.tsx b/src/features/ui/util/react-router-helpers.tsx index 02a5fb180..e202af4a4 100644 --- a/src/features/ui/util/react-router-helpers.tsx +++ b/src/features/ui/util/react-router-helpers.tsx @@ -4,7 +4,6 @@ import { Redirect, Route, useHistory, RouteProps, RouteComponentProps, match as import { Layout } from 'soapbox/components/ui'; import { useOwnAccount, useSettings } from 'soapbox/hooks'; -import BundleColumnError from '../components/bundle-column-error'; import ColumnForbidden from '../components/column-forbidden'; import ColumnLoading from '../components/column-loading'; import ColumnsArea from '../components/columns-area'; @@ -48,7 +47,7 @@ const WrappedRoute: React.FC = ({ const renderComponent = ({ match }: RouteComponentProps) => { if (Page) { return ( - + {Component => ( @@ -63,7 +62,7 @@ const WrappedRoute: React.FC = ({ } return ( - + {Component => ( @@ -89,7 +88,6 @@ const WrappedRoute: React.FC = ({ const renderLoading = () => renderWithLayout(); const renderForbidden = () => renderWithLayout(); - const renderError = (props: any) => renderWithLayout(); const loginRedirect = () => { const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`); diff --git a/src/pages/event-page.tsx b/src/pages/event-page.tsx index f10a865fa..a8fd7bb4b 100644 --- a/src/pages/event-page.tsx +++ b/src/pages/event-page.tsx @@ -31,7 +31,7 @@ const EventPage: React.FC = ({ params, children }) => { const history = useHistory(); const statusId = params?.statusId!; - const status = useAppSelector(state => getStatus(state, { id: statusId })); + const status = useAppSelector(state => getStatus(state, { id: statusId }) || undefined); const event = status?.event; diff --git a/src/pages/group-page.tsx b/src/pages/group-page.tsx index 5124076be..fac6ca6a4 100644 --- a/src/pages/group-page.tsx +++ b/src/pages/group-page.tsx @@ -3,7 +3,6 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; import { useRouteMatch } from 'react-router-dom'; import { useGroup, useGroupMembershipRequests } from 'soapbox/api/hooks'; -import GroupLookupHoc from 'soapbox/components/hoc/group-lookup-hoc'; import { Column, Icon, Layout, Stack, Text, Tabs } from 'soapbox/components/ui'; import GroupHeader from 'soapbox/features/group/components/group-header'; import LinkFooter from 'soapbox/features/ui/components/link-footer'; @@ -191,4 +190,4 @@ const GroupPage: React.FC = ({ params, children }) => { ); }; -export default GroupLookupHoc(GroupPage as any) as any; +export default GroupPage; diff --git a/src/pages/remote-instance-page.tsx b/src/pages/remote-instance-page.tsx index 60a61e16d..b53844213 100644 --- a/src/pages/remote-instance-page.tsx +++ b/src/pages/remote-instance-page.tsx @@ -13,15 +13,15 @@ import { federationRestrictionsDisclosed } from 'soapbox/utils/state'; import { Layout } from '../components/ui'; interface IRemoteInstancePage { - params: { - instance: string; + params?: { + instance?: string; }; children: React.ReactNode; } /** Page for viewing a remote instance timeline. */ const RemoteInstancePage: React.FC = ({ children, params }) => { - const host = params.instance; + const host = params!.instance!; const { account } = useOwnAccount(); const disclosed = useAppSelector(federationRestrictionsDisclosed); From b02c39da2d5a642763083b257c35f23ad20a233e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 7 Oct 2023 17:14:45 -0500 Subject: [PATCH 6/7] Delete Bundle component, use Suspense and React.lazy --- src/actions/bundles.ts | 28 ------- src/components/attachment-thumbs.tsx | 27 +++---- src/components/birthday-input.tsx | 25 +++--- src/components/profile-hover-card.tsx | 15 ++-- src/components/status-media.tsx | 78 +++++++++---------- src/containers/soapbox.tsx | 14 ++-- .../chats/components/chat-message.tsx | 24 +++--- .../compose/components/compose-form.tsx | 36 ++++----- .../compose/components/schedule-form.tsx | 31 ++++---- .../containers/schedule-form-container.tsx | 14 ---- .../report/components/status-check-box.tsx | 51 +++++------- src/features/ui/components/bundle.tsx | 23 ------ src/features/ui/components/modal-loading.tsx | 2 - src/features/ui/components/modal-root.tsx | 16 ++-- .../compose-event-modal.tsx | 71 ++++++++--------- .../modals/edit-announcement-modal.tsx | 45 +++++------ .../ui/components/pinned-accounts-panel.tsx | 5 +- src/features/ui/components/profile-field.tsx | 13 +--- .../ui/containers/bundle-container.tsx | 3 - src/features/ui/index.tsx | 26 ++----- src/features/ui/util/react-router-helpers.tsx | 41 ++++------ src/pages/admin-page.tsx | 6 +- src/pages/default-page.tsx | 17 +--- src/pages/event-page.tsx | 21 ++--- src/pages/events-page.tsx | 13 +--- src/pages/group-page.tsx | 19 ++--- src/pages/groups-page.tsx | 23 +----- src/pages/groups-pending-page.tsx | 13 +--- src/pages/home-page.tsx | 39 +++------- src/pages/landing-page.tsx | 13 +--- src/pages/manage-groups-page.tsx | 10 +-- src/pages/profile-page.tsx | 34 ++------ src/pages/remote-instance-page.tsx | 15 +--- src/pages/search-page.tsx | 23 ++---- src/pages/status-page.tsx | 19 ++--- 35 files changed, 275 insertions(+), 578 deletions(-) delete mode 100644 src/actions/bundles.ts delete mode 100644 src/features/compose/containers/schedule-form-container.tsx delete mode 100644 src/features/ui/components/bundle.tsx delete mode 100644 src/features/ui/containers/bundle-container.tsx diff --git a/src/actions/bundles.ts b/src/actions/bundles.ts deleted file mode 100644 index fc5ef9321..000000000 --- a/src/actions/bundles.ts +++ /dev/null @@ -1,28 +0,0 @@ -const BUNDLE_FETCH_REQUEST = 'BUNDLE_FETCH_REQUEST'; -const BUNDLE_FETCH_SUCCESS = 'BUNDLE_FETCH_SUCCESS'; -const BUNDLE_FETCH_FAIL = 'BUNDLE_FETCH_FAIL'; - -const fetchBundleRequest = (skipLoading?: boolean) => ({ - type: BUNDLE_FETCH_REQUEST, - skipLoading, -}); - -const fetchBundleSuccess = (skipLoading?: boolean) => ({ - type: BUNDLE_FETCH_SUCCESS, - skipLoading, -}); - -const fetchBundleFail = (error: any, skipLoading?: boolean) => ({ - type: BUNDLE_FETCH_FAIL, - error, - skipLoading, -}); - -export { - BUNDLE_FETCH_REQUEST, - BUNDLE_FETCH_SUCCESS, - BUNDLE_FETCH_FAIL, - fetchBundleRequest, - fetchBundleSuccess, - fetchBundleFail, -}; diff --git a/src/components/attachment-thumbs.tsx b/src/components/attachment-thumbs.tsx index 1ec694667..c5a017408 100644 --- a/src/components/attachment-thumbs.tsx +++ b/src/components/attachment-thumbs.tsx @@ -1,7 +1,6 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import { openModal } from 'soapbox/actions/modals'; -import Bundle from 'soapbox/features/ui/components/bundle'; import { MediaGallery } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch } from 'soapbox/hooks'; @@ -18,23 +17,21 @@ const AttachmentThumbs = (props: IAttachmentThumbs) => { const { media, onClick, sensitive } = props; const dispatch = useAppDispatch(); - const renderLoading = () =>

; + const fallback =
; const onOpenMedia = (media: ImmutableList, index: number) => dispatch(openModal('MEDIA', { media, index })); return (
- - {(Component: any) => ( - - )} - + + + {onClick && (
diff --git a/src/components/birthday-input.tsx b/src/components/birthday-input.tsx index a35e85055..62043bd51 100644 --- a/src/components/birthday-input.tsx +++ b/src/components/birthday-input.tsx @@ -2,7 +2,6 @@ import React, { useMemo } from 'react'; import { defineMessages, useIntl } from 'react-intl'; import IconButton from 'soapbox/components/icon-button'; -import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import { DatePicker } from 'soapbox/features/ui/util/async-components'; import { useInstance, useFeatures } from 'soapbox/hooks'; @@ -114,19 +113,17 @@ const BirthdayInput: React.FC = ({ value, onChange, required }) return (
- - {Component => ()} - +
); }; diff --git a/src/components/profile-hover-card.tsx b/src/components/profile-hover-card.tsx index ddb89e11e..9c06dd92c 100644 --- a/src/components/profile-hover-card.tsx +++ b/src/components/profile-hover-card.tsx @@ -12,7 +12,6 @@ import { import { useAccount, usePatronUser } from 'soapbox/api/hooks'; import Badge from 'soapbox/components/badge'; import ActionButton from 'soapbox/features/ui/components/action-button'; -import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import { UserPanel } from 'soapbox/features/ui/util/async-components'; import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; import { isLocal } from 'soapbox/utils/accounts'; @@ -112,15 +111,11 @@ export const ProfileHoverCard: React.FC = ({ visible = true } - - {Component => ( - } - badges={badges} - /> - )} - + } + badges={badges} + /> {isLocal(account) ? ( diff --git a/src/components/status-media.tsx b/src/components/status-media.tsx index 00975e224..7147e3a54 100644 --- a/src/components/status-media.tsx +++ b/src/components/status-media.tsx @@ -1,16 +1,14 @@ -import React from 'react'; +import React, { Suspense } from 'react'; import { openModal } from 'soapbox/actions/modals'; import AttachmentThumbs from 'soapbox/components/attachment-thumbs'; import { GroupLinkPreview } from 'soapbox/features/groups/components/group-link-preview'; import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder-card'; import Card from 'soapbox/features/status/components/card'; -import Bundle from 'soapbox/features/ui/components/bundle'; import { MediaGallery, Video, Audio } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch } from 'soapbox/hooks'; import type { List as ImmutableList } from 'immutable'; -import type VideoType from 'soapbox/features/video'; import type { Status, Attachment } from 'soapbox/types/entities'; interface IStatusMedia { @@ -70,54 +68,48 @@ const StatusMedia: React.FC = ({ const video = firstAttachment; media = ( - - {(Component: typeof VideoType) => ( - - )} - + + ); } else if (size === 1 && firstAttachment.type === 'audio') { const attachment = firstAttachment; media = ( - - {(Component: any) => ( - - )} - + + ); } else { media = ( - - {(Component: any) => ( - - )} - + + + ); } } else if (status.spoiler_text.length === 0 && !status.quote && status.card?.group) { diff --git a/src/containers/soapbox.tsx b/src/containers/soapbox.tsx index 9df5b7a19..d60f8eec0 100644 --- a/src/containers/soapbox.tsx +++ b/src/containers/soapbox.tsx @@ -1,6 +1,6 @@ import { QueryClientProvider } from '@tanstack/react-query'; import clsx from 'clsx'; -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, Suspense } from 'react'; import { Toaster } from 'react-hot-toast'; import { IntlProvider } from 'react-intl'; import { Provider } from 'react-redux'; @@ -18,7 +18,6 @@ import Helmet from 'soapbox/components/helmet'; import LoadingScreen from 'soapbox/components/loading-screen'; import { StatProvider } from 'soapbox/contexts/stat-context'; import EmbeddedStatus from 'soapbox/features/embedded-status'; -import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import { ModalContainer, OnboardingWizard, @@ -87,9 +86,9 @@ const SoapboxMount = () => { /** Render the onboarding flow. */ const renderOnboarding = () => ( - - {(Component) => } - + }> + + ); /** Render the auth layout or UI. */ @@ -127,10 +126,7 @@ const SoapboxMount = () => { {renderBody()} - - {Component => } - - +
diff --git a/src/features/chats/components/chat-message.tsx b/src/features/chats/components/chat-message.tsx index 373be7f12..9b65eabf9 100644 --- a/src/features/chats/components/chat-message.tsx +++ b/src/features/chats/components/chat-message.tsx @@ -10,7 +10,6 @@ import { initReport, ReportableEntities } from 'soapbox/actions/reports'; import DropdownMenu from 'soapbox/components/dropdown-menu'; import { HStack, Icon, Stack, Text } from 'soapbox/components/ui'; import emojify from 'soapbox/features/emoji'; -import Bundle from 'soapbox/features/ui/components/bundle'; import { MediaGallery } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks'; import { ChatKeys, IChat, useChatActions } from 'soapbox/queries/chats'; @@ -22,7 +21,6 @@ import ChatMessageReaction from './chat-message-reaction'; import ChatMessageReactionWrapper from './chat-message-reaction-wrapper/chat-message-reaction-wrapper'; import type { Menu as IMenu } from 'soapbox/components/dropdown-menu'; -import type { IMediaGallery } from 'soapbox/components/media-gallery'; import type { ChatMessage as ChatMessageEntity } from 'soapbox/types/entities'; const messages = defineMessages({ @@ -111,19 +109,15 @@ const ChatMessage = (props: IChatMessage) => { if (!chatMessage.media_attachments.size) return null; return ( - - {(Component: React.FC) => ( - - )} - + ); }; diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 849f6cf80..97bb5d958 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -17,14 +17,12 @@ import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest import AutosuggestTextarea from 'soapbox/components/autosuggest-textarea'; import { Button, HStack, Stack } from 'soapbox/components/ui'; import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container'; -import Bundle from 'soapbox/features/ui/components/bundle'; -import { ComposeEditor } from 'soapbox/features/ui/util/async-components'; +import { ComposeEditor, ScheduleForm } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks'; import { isMobile } from 'soapbox/is-mobile'; import QuotedStatusContainer from '../containers/quoted-status-container'; import ReplyIndicatorContainer from '../containers/reply-indicator-container'; -import ScheduleFormContainer from '../containers/schedule-form-container'; import UploadButtonContainer from '../containers/upload-button-container'; import WarningContainer from '../containers/warning-container'; import { $createEmojiNode } from '../editor/nodes/emoji-node'; @@ -260,7 +258,7 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab ref={spoilerTextRef} /> - + ); @@ -313,23 +311,19 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab {!shouldCondense && !event && !group && }
- - {(Component: any) => ( - - )} - + {composeModifiers}
diff --git a/src/features/compose/components/schedule-form.tsx b/src/features/compose/components/schedule-form.tsx index 074d1b234..aab6b8864 100644 --- a/src/features/compose/components/schedule-form.tsx +++ b/src/features/compose/components/schedule-form.tsx @@ -5,7 +5,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { setSchedule, removeSchedule } from 'soapbox/actions/compose'; import IconButton from 'soapbox/components/icon-button'; import { HStack, Stack, Text } from 'soapbox/components/ui'; -import BundleContainer from 'soapbox/features/ui/containers/bundle-container'; import { DatePicker } from 'soapbox/features/ui/util/async-components'; import { useAppDispatch, useCompose } from 'soapbox/hooks'; @@ -55,22 +54,20 @@ const ScheduleForm: React.FC = ({ composeId }) => { - - {Component => ()} - + = (props) => ( - - {Component => } - -); - -export default ScheduleFormContainer; diff --git a/src/features/report/components/status-check-box.tsx b/src/features/report/components/status-check-box.tsx index d8d9c0eb4..b8cb48015 100644 --- a/src/features/report/components/status-check-box.tsx +++ b/src/features/report/components/status-check-box.tsx @@ -6,7 +6,6 @@ import StatusContent from 'soapbox/components/status-content'; import { Toggle } from 'soapbox/components/ui'; import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import Bundle from '../../ui/components/bundle'; import { MediaGallery, Video, Audio } from '../../ui/util/async-components'; interface IStatusCheckBox { @@ -35,22 +34,16 @@ const StatusCheckBox: React.FC = ({ id, disabled }) => { if (video) { media = ( - - {(Component: any) => ( - - )} - +