From cd1ec65286ae7c896a687638fa9fd8ad21438e21 Mon Sep 17 00:00:00 2001 From: twwu Date: Wed, 16 Jul 2025 16:51:55 +0800 Subject: [PATCH] feat: convert components to dynamic imports for improved performance --- web/app/(commonLayout)/apps/AppCard.tsx | 26 ++++-- web/app/(commonLayout)/apps/Apps.tsx | 10 +- web/app/(commonLayout)/apps/NewAppCard.tsx | 103 ++++++++++++--------- web/context/modal-context.tsx | 50 +++++++--- 4 files changed, 125 insertions(+), 64 deletions(-) diff --git a/web/app/(commonLayout)/apps/AppCard.tsx b/web/app/(commonLayout)/apps/AppCard.tsx index e04c3fdea6..bdb9f3abe4 100644 --- a/web/app/(commonLayout)/apps/AppCard.tsx +++ b/web/app/(commonLayout)/apps/AppCard.tsx @@ -7,10 +7,8 @@ import { useTranslation } from 'react-i18next' import { RiBuildingLine, RiGlobalLine, RiLockLine, RiMoreFill, RiVerifiedBadgeLine } from '@remixicon/react' import cn from '@/utils/classnames' import type { App } from '@/types/app' -import Confirm from '@/app/components/base/confirm' import Toast, { ToastContext } from '@/app/components/base/toast' import { copyApp, deleteApp, exportAppConfig, updateAppInfo } from '@/service/apps' -import DuplicateAppModal from '@/app/components/app/duplicate-modal' import type { DuplicateAppModalProps } from '@/app/components/app/duplicate-modal' import AppIcon from '@/app/components/base/app-icon' import AppsContext, { useAppContext } from '@/context/app-context' @@ -22,21 +20,37 @@ import { getRedirection } from '@/utils/app-redirection' import { useProviderContext } from '@/context/provider-context' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import type { CreateAppModalProps } from '@/app/components/explore/create-app-modal' -import EditAppModal from '@/app/components/explore/create-app-modal' -import SwitchAppModal from '@/app/components/app/switch-app-modal' import type { Tag } from '@/app/components/base/tag-management/constant' import TagSelector from '@/app/components/base/tag-management/selector' import type { EnvironmentVariable } from '@/app/components/workflow/types' -import DSLExportConfirmModal from '@/app/components/workflow/dsl-export-confirm-modal' import { fetchWorkflowDraft } from '@/service/workflow' import { fetchInstalledAppList } from '@/service/explore' import { AppTypeIcon } from '@/app/components/app/type-selector' import Tooltip from '@/app/components/base/tooltip' -import AccessControl from '@/app/components/app/app-access-control' import { AccessMode } from '@/models/access-control' import { useGlobalPublicStore } from '@/context/global-public-context' import { formatTime } from '@/utils/time' import { useGetUserCanAccessApp } from '@/service/access-control' +import dynamic from 'next/dynamic' + +const EditAppModal = dynamic(() => import('@/app/components/explore/create-app-modal'), { + ssr: false, +}) +const DuplicateAppModal = dynamic(() => import('@/app/components/app/duplicate-modal'), { + ssr: false, +}) +const SwitchAppModal = dynamic(() => import('@/app/components/app/switch-app-modal'), { + ssr: false, +}) +const Confirm = dynamic(() => import('@/app/components/base/confirm'), { + ssr: false, +}) +const DSLExportConfirmModal = dynamic(() => import('@/app/components/workflow/dsl-export-confirm-modal'), { + ssr: false, +}) +const AccessControl = dynamic(() => import('@/app/components/app/app-access-control'), { + ssr: false, +}) export type AppCardProps = { app: App diff --git a/web/app/(commonLayout)/apps/Apps.tsx b/web/app/(commonLayout)/apps/Apps.tsx index 2aa192fb02..9dc8c16097 100644 --- a/web/app/(commonLayout)/apps/Apps.tsx +++ b/web/app/(commonLayout)/apps/Apps.tsx @@ -28,10 +28,16 @@ import TabSliderNew from '@/app/components/base/tab-slider-new' import { useTabSearchParams } from '@/hooks/use-tab-searchparams' import Input from '@/app/components/base/input' import { useStore as useTagStore } from '@/app/components/base/tag-management/store' -import TagManagementModal from '@/app/components/base/tag-management' import TagFilter from '@/app/components/base/tag-management/filter' import CheckboxWithLabel from '@/app/components/datasets/create/website/base/checkbox-with-label' -import CreateFromDSLModal from '@/app/components/app/create-from-dsl-modal' +import dynamic from 'next/dynamic' + +const TagManagementModal = dynamic(() => import('@/app/components/base/tag-management'), { + ssr: false, +}) +const CreateFromDSLModal = dynamic(() => import('@/app/components/app/create-from-dsl-modal'), { + ssr: false, +}) const getKey = ( pageIndex: number, diff --git a/web/app/(commonLayout)/apps/NewAppCard.tsx b/web/app/(commonLayout)/apps/NewAppCard.tsx index 0b42577ee3..2761a257e9 100644 --- a/web/app/(commonLayout)/apps/NewAppCard.tsx +++ b/web/app/(commonLayout)/apps/NewAppCard.tsx @@ -6,12 +6,21 @@ import { useSearchParams, } from 'next/navigation' import { useTranslation } from 'react-i18next' -import CreateAppTemplateDialog from '@/app/components/app/create-app-dialog' -import CreateAppModal from '@/app/components/app/create-app-modal' -import CreateFromDSLModal, { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal' +import { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal' import { useProviderContext } from '@/context/provider-context' import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files' import cn from '@/utils/classnames' +import dynamic from 'next/dynamic' + +const CreateAppModal = dynamic(() => import('@/app/components/app/create-app-modal'), { + ssr: false, +}) +const CreateAppTemplateDialog = dynamic(() => import('@/app/components/app/create-app-dialog'), { + ssr: false, +}) +const CreateFromDSLModal = dynamic(() => import('@/app/components/app/create-from-dsl-modal'), { + ssr: false, +}) export type CreateAppCardProps = { className?: string @@ -67,48 +76,54 @@ const CreateAppCard = ( - setShowNewAppModal(false)} - onSuccess={() => { - onPlanInfoChanged() - if (onSuccess) - onSuccess() - }} - onCreateFromTemplate={() => { - setShowNewAppTemplateDialog(true) - setShowNewAppModal(false) - }} - /> - setShowNewAppTemplateDialog(false)} - onSuccess={() => { - onPlanInfoChanged() - if (onSuccess) - onSuccess() - }} - onCreateFromBlank={() => { - setShowNewAppModal(true) - setShowNewAppTemplateDialog(false) - }} - /> - { - setShowCreateFromDSLModal(false) + {showNewAppModal && ( + setShowNewAppModal(false)} + onSuccess={() => { + onPlanInfoChanged() + if (onSuccess) + onSuccess() + }} + onCreateFromTemplate={() => { + setShowNewAppTemplateDialog(true) + setShowNewAppModal(false) + }} + /> + )} + {showNewAppTemplateDialog && ( + setShowNewAppTemplateDialog(false)} + onSuccess={() => { + onPlanInfoChanged() + if (onSuccess) + onSuccess() + }} + onCreateFromBlank={() => { + setShowNewAppModal(true) + setShowNewAppTemplateDialog(false) + }} + /> + )} + {showCreateFromDSLModal && ( + { + setShowCreateFromDSLModal(false) - if (dslUrl) - replace('/') - }} - activeTab={activeTab} - dslUrl={dslUrl} - onSuccess={() => { - onPlanInfoChanged() - if (onSuccess) - onSuccess() - }} - /> + if (dslUrl) + replace('/') + }} + activeTab={activeTab} + dslUrl={dslUrl} + onSuccess={() => { + onPlanInfoChanged() + if (onSuccess) + onSuccess() + }} + /> + )} ) } diff --git a/web/context/modal-context.tsx b/web/context/modal-context.tsx index d86590335d..f6425ec11f 100644 --- a/web/context/modal-context.tsx +++ b/web/context/modal-context.tsx @@ -4,13 +4,6 @@ import type { Dispatch, SetStateAction } from 'react' import { useCallback, useState } from 'react' import { createContext, useContext, useContextSelector } from 'use-context-selector' import { useRouter, useSearchParams } from 'next/navigation' -import AccountSetting from '@/app/components/header/account-setting' -import ApiBasedExtensionModal from '@/app/components/header/account-setting/api-based-extension-page/modal' -import ModerationSettingModal from '@/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal' -import ExternalDataToolModal from '@/app/components/app/configuration/tools/external-data-tool-modal' -import AnnotationFullModal from '@/app/components/billing/annotation-full/modal' -import ModelModal from '@/app/components/header/account-setting/model-provider-page/model-modal' -import ExternalAPIModal from '@/app/components/datasets/external-api/external-api-modal' import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, @@ -20,23 +13,56 @@ import type { import { EDUCATION_VERIFYING_LOCALSTORAGE_ITEM, } from '@/app/education-apply/constants' -import Pricing from '@/app/components/billing/pricing' import type { ModerationConfig, PromptVariable } from '@/models/debug' import type { ApiBasedExtension, ExternalDataTool, } from '@/models/common' import type { CreateExternalAPIReq } from '@/app/components/datasets/external-api/declarations' -import ModelLoadBalancingEntryModal from '@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal' import type { ModelLoadBalancingModalProps } from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal' -import ModelLoadBalancingModal from '@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal' -import OpeningSettingModal from '@/app/components/base/features/new-feature-panel/conversation-opener/modal' import type { OpeningStatement } from '@/app/components/base/features/types' import type { InputVar } from '@/app/components/workflow/types' import type { UpdatePluginPayload } from '@/app/components/plugins/types' -import UpdatePlugin from '@/app/components/plugins/update-plugin' import { removeSpecificQueryParam } from '@/utils' import { noop } from 'lodash-es' +import dynamic from 'next/dynamic' + +const AccountSetting = dynamic(() => import('@/app/components/header/account-setting'), { + ssr: false, +}) +const ApiBasedExtensionModal = dynamic(() => import('@/app/components/header/account-setting/api-based-extension-page/modal'), { + ssr: false, +}) +const ModerationSettingModal = dynamic(() => import('@/app/components/base/features/new-feature-panel/moderation/moderation-setting-modal'), { + ssr: false, +}) +const ExternalDataToolModal = dynamic(() => import('@/app/components/app/configuration/tools/external-data-tool-modal'), { + ssr: false, +}) +const Pricing = dynamic(() => import('@/app/components/billing/pricing'), { + ssr: false, +}) +const AnnotationFullModal = dynamic(() => import('@/app/components/billing/annotation-full/modal'), { + ssr: false, +}) +const ModelModal = dynamic(() => import('@/app/components/header/account-setting/model-provider-page/model-modal'), { + ssr: false, +}) +const ExternalAPIModal = dynamic(() => import('@/app/components/datasets/external-api/external-api-modal'), { + ssr: false, +}) +const ModelLoadBalancingModal = dynamic(() => import('@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'), { + ssr: false, +}) +const ModelLoadBalancingEntryModal = dynamic(() => import('@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal'), { + ssr: false, +}) +const OpeningSettingModal = dynamic(() => import('@/app/components/base/features/new-feature-panel/conversation-opener/modal'), { + ssr: false, +}) +const UpdatePlugin = dynamic(() => import('@/app/components/plugins/update-plugin'), { + ssr: false, +}) export type ModalState = { payload: T