Improve lazy loading (#12393)
Creating manual chunk was a bad idea, we should always solve lazy loading problem at the source instance. Setting a 4.5MB for the index bundle size, CI will fail if we go above. There is still a lot of room for optimizations! - More agressive lazy loading (e.g. xyflow and tiptap are still loaded in index!) - Add a prefetch mechanism - Add stronger CI checks to make sure libraries we've set asides are not added back - Fix AllIcons component with does not work as intended (loaded on initial load)
This commit is contained in:
@ -3,7 +3,7 @@ import { useMemo } from 'react';
|
||||
import { FormSelectFieldInput } from '@/object-record/record-field/form-types/components/FormSelectFieldInput';
|
||||
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||
import { useCountries } from '@/ui/input/components/internal/hooks/useCountries';
|
||||
import { CountryCode } from 'libphonenumber-js';
|
||||
import type { CountryCode } from 'libphonenumber-js';
|
||||
import { IconCircleOff, IconComponentProps } from 'twenty-ui/display';
|
||||
import { SelectOption } from 'twenty-ui/input';
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useRichTextV2FieldDisplay } from '@/object-record/record-field/meta-types/hooks/useRichTextV2FieldDisplay';
|
||||
import { getFirstNonEmptyLineOfRichText } from '@/ui/input/editor/utils/getFirstNonEmptyLineOfRichText';
|
||||
import { PartialBlock } from '@blocknote/core';
|
||||
import type { PartialBlock } from '@blocknote/core';
|
||||
import { isDefined, parseJson } from 'twenty-shared/utils';
|
||||
|
||||
export const RichTextV2FieldDisplay = () => {
|
||||
|
||||
@ -9,7 +9,7 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
|
||||
import { isFieldRichText } from '@/object-record/record-field/types/guards/isFieldRichText';
|
||||
import { isFieldRichTextValue } from '@/object-record/record-field/types/guards/isFieldRichTextValue';
|
||||
import { PartialBlock } from '@blocknote/core';
|
||||
import type { PartialBlock } from '@blocknote/core';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
|
||||
@ -5,7 +5,7 @@ import { useRecordFieldValue } from '@/object-record/record-store/contexts/Recor
|
||||
import { FieldRichTextValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { assertFieldMetadata } from '@/object-record/record-field/types/guards/assertFieldMetadata';
|
||||
import { isFieldRichText } from '@/object-record/record-field/types/guards/isFieldRichText';
|
||||
import { PartialBlock } from '@blocknote/core';
|
||||
import type { PartialBlock } from '@blocknote/core';
|
||||
import { isDefined, parseJson } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
|
||||
@ -12,7 +12,7 @@ import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { usePersistField } from '@/object-record/record-field/hooks/usePersistField';
|
||||
import { isFieldRichTextV2 } from '@/object-record/record-field/types/guards/isFieldRichTextV2';
|
||||
import { isFieldRichTextV2Value } from '@/object-record/record-field/types/guards/isFieldRichTextValueV2';
|
||||
import { PartialBlock } from '@blocknote/core';
|
||||
import type { PartialBlock } from '@blocknote/core';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { FieldContext } from '../../contexts/FieldContext';
|
||||
import { assertFieldMetadata } from '../../types/guards/assertFieldMetadata';
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ActivityRichTextEditor } from '@/activities/components/ActivityRichTextEditor';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
|
||||
import { useRichTextCommandMenu } from '@/command-menu/hooks/useRichTextCommandMenu';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
@ -8,11 +8,19 @@ import {
|
||||
FieldInputEvent,
|
||||
} from '@/object-record/record-field/types/FieldInputEvent';
|
||||
import { DEFAULT_CELL_SCOPE } from '@/object-record/record-table/record-table-cell/hooks/useOpenRecordTableCellV2';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRef } from 'react';
|
||||
import { lazy, Suspense, useRef } from 'react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import { IconLayoutSidebarLeftCollapse } from 'twenty-ui/display';
|
||||
import { FloatingIconButton } from 'twenty-ui/input';
|
||||
|
||||
const ActivityRichTextEditor = lazy(() =>
|
||||
import('@/activities/components/ActivityRichTextEditor').then((module) => ({
|
||||
default: module.ActivityRichTextEditor,
|
||||
})),
|
||||
);
|
||||
|
||||
export type RichTextFieldInputProps = {
|
||||
onClickOutside?: FieldInputClickOutsideEvent;
|
||||
onCancel?: () => void;
|
||||
@ -38,6 +46,19 @@ const StyledCollapseButton = styled.div`
|
||||
display: flex;
|
||||
`;
|
||||
|
||||
const LoadingSkeleton = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={theme.border.radius.sm}
|
||||
>
|
||||
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.s} />
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
export const RichTextFieldInput = ({
|
||||
targetableObject,
|
||||
onClickOutside,
|
||||
@ -70,10 +91,12 @@ export const RichTextFieldInput = ({
|
||||
|
||||
return (
|
||||
<StyledContainer ref={containerRef}>
|
||||
<ActivityRichTextEditor
|
||||
activityId={targetableObject.id}
|
||||
activityObjectNameSingular={targetableObject.targetObjectNameSingular}
|
||||
/>
|
||||
<Suspense fallback={<LoadingSkeleton />}>
|
||||
<ActivityRichTextEditor
|
||||
activityId={targetableObject.id}
|
||||
activityObjectNameSingular={targetableObject.targetObjectNameSingular}
|
||||
/>
|
||||
</Suspense>
|
||||
<StyledCollapseButton>
|
||||
<FloatingIconButton
|
||||
Icon={IconLayoutSidebarLeftCollapse}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { Calendar } from '@/activities/calendar/components/Calendar';
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { EmailThreads } from '@/activities/emails/components/EmailThreads';
|
||||
import { Attachments } from '@/activities/files/components/Attachments';
|
||||
import { Notes } from '@/activities/notes/components/Notes';
|
||||
@ -10,16 +11,15 @@ import { CardType } from '@/object-record/record-show/types/CardType';
|
||||
import { ListenRecordUpdatesEffect } from '@/subscription/components/ListenUpdatesEffect';
|
||||
import { ShowPageActivityContainer } from '@/ui/layout/show-page/components/ShowPageActivityContainer';
|
||||
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||
import { WorkflowRunVisualizer } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizer';
|
||||
import { WorkflowRunVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowRunVisualizerEffect';
|
||||
import { WorkflowVersionVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizer';
|
||||
import { WorkflowVersionVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVersionVisualizerEffect';
|
||||
import { WorkflowVisualizer } from '@/workflow/workflow-diagram/components/WorkflowVisualizer';
|
||||
import { WorkflowVisualizerEffect } from '@/workflow/workflow-diagram/components/WorkflowVisualizerEffect';
|
||||
import { WorkflowRunVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowRunVisualizerComponentInstanceContext';
|
||||
import { WorkflowVisualizerComponentInstanceContext } from '@/workflow/workflow-diagram/states/contexts/WorkflowVisualizerComponentInstanceContext';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useId } from 'react';
|
||||
import { lazy, Suspense, useId } from 'react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
const StyledGreyBox = styled.div<{ isInRightDrawer?: boolean }>`
|
||||
background: ${({ theme, isInRightDrawer }) =>
|
||||
@ -34,6 +34,15 @@ const StyledGreyBox = styled.div<{ isInRightDrawer?: boolean }>`
|
||||
isInRightDrawer ? theme.spacing(4) : ''};
|
||||
`;
|
||||
|
||||
const StyledLoadingSkeletonContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
height: 100%;
|
||||
padding: ${({ theme }) => theme.spacing(4)};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
type CardComponentProps = {
|
||||
targetableObject: Pick<
|
||||
ActivityTargetableObject,
|
||||
@ -44,6 +53,48 @@ type CardComponentProps = {
|
||||
|
||||
type CardComponentType = (props: CardComponentProps) => JSX.Element | null;
|
||||
|
||||
const LoadingSkeleton = () => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledLoadingSkeletonContainer>
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={theme.border.radius.sm}
|
||||
>
|
||||
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.m} />
|
||||
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.m} />
|
||||
<Skeleton height={SKELETON_LOADER_HEIGHT_SIZES.standard.m} />
|
||||
</SkeletonTheme>
|
||||
</StyledLoadingSkeletonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const WorkflowVisualizer = lazy(() =>
|
||||
import('@/workflow/workflow-diagram/components/WorkflowVisualizer').then(
|
||||
(module) => ({
|
||||
default: module.WorkflowVisualizer,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
const WorkflowVersionVisualizer = lazy(() =>
|
||||
import(
|
||||
'@/workflow/workflow-diagram/components/WorkflowVersionVisualizer'
|
||||
).then((module) => ({
|
||||
default: module.WorkflowVersionVisualizer,
|
||||
})),
|
||||
);
|
||||
|
||||
const WorkflowRunVisualizer = lazy(() =>
|
||||
import('@/workflow/workflow-diagram/components/WorkflowRunVisualizer').then(
|
||||
(module) => ({
|
||||
default: module.WorkflowRunVisualizer,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
export const CardComponents: Record<CardType, CardComponentType> = {
|
||||
[CardType.TimelineCard]: ({ targetableObject, isInRightDrawer }) => (
|
||||
<TimelineActivities
|
||||
@ -95,7 +146,9 @@ export const CardComponents: Record<CardType, CardComponentType> = {
|
||||
}}
|
||||
>
|
||||
<WorkflowVisualizerEffect workflowId={targetableObject.id} />
|
||||
<WorkflowVisualizer workflowId={targetableObject.id} />
|
||||
<Suspense fallback={<LoadingSkeleton />}>
|
||||
<WorkflowVisualizer workflowId={targetableObject.id} />
|
||||
</Suspense>
|
||||
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||
);
|
||||
},
|
||||
@ -112,7 +165,9 @@ export const CardComponents: Record<CardType, CardComponentType> = {
|
||||
<WorkflowVersionVisualizerEffect
|
||||
workflowVersionId={targetableObject.id}
|
||||
/>
|
||||
<WorkflowVersionVisualizer workflowVersionId={targetableObject.id} />
|
||||
<Suspense fallback={<LoadingSkeleton />}>
|
||||
<WorkflowVersionVisualizer workflowVersionId={targetableObject.id} />
|
||||
</Suspense>
|
||||
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||
);
|
||||
},
|
||||
@ -139,7 +194,9 @@ export const CardComponents: Record<CardType, CardComponentType> = {
|
||||
recordId={targetableObject.id}
|
||||
listenedFields={['status', 'output']}
|
||||
/>
|
||||
<WorkflowRunVisualizer workflowRunId={targetableObject.id} />
|
||||
<Suspense fallback={<LoadingSkeleton />}>
|
||||
<WorkflowRunVisualizer workflowRunId={targetableObject.id} />
|
||||
</Suspense>
|
||||
</WorkflowRunVisualizerComponentInstanceContext.Provider>
|
||||
</WorkflowVisualizerComponentInstanceContext.Provider>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user