Skip to content

Commit 19a8dae

Browse files
authored
improvement(performance): used react scan to identify rerendering issues and react issues (#2873)
1 parent 0fcd526 commit 19a8dae

File tree

51 files changed

+2985
-3345
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2985
-3345
lines changed

apps/sim/app/chat/components/message/components/markdown-renderer.tsx

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { type HTMLAttributes, type ReactNode } from 'react'
1+
import React, { type HTMLAttributes, memo, type ReactNode, useMemo } from 'react'
22
import ReactMarkdown from 'react-markdown'
33
import remarkGfm from 'remark-gfm'
44
import { Tooltip } from '@/components/emcn'
@@ -23,24 +23,16 @@ export function LinkWithPreview({ href, children }: { href: string; children: Re
2323
)
2424
}
2525

26-
export default function MarkdownRenderer({
27-
content,
28-
customLinkComponent,
29-
}: {
30-
content: string
31-
customLinkComponent?: typeof LinkWithPreview
32-
}) {
33-
const LinkComponent = customLinkComponent || LinkWithPreview
26+
const REMARK_PLUGINS = [remarkGfm]
3427

35-
const customComponents = {
36-
// Paragraph
28+
function createCustomComponents(LinkComponent: typeof LinkWithPreview) {
29+
return {
3730
p: ({ children }: React.HTMLAttributes<HTMLParagraphElement>) => (
3831
<p className='mb-1 font-sans text-base text-gray-800 leading-relaxed last:mb-0 dark:text-gray-200'>
3932
{children}
4033
</p>
4134
),
4235

43-
// Headings
4436
h1: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
4537
<h1 className='mt-10 mb-5 font-sans font-semibold text-2xl text-gray-900 dark:text-gray-100'>
4638
{children}
@@ -62,7 +54,6 @@ export default function MarkdownRenderer({
6254
</h4>
6355
),
6456

65-
// Lists
6657
ul: ({ children }: React.HTMLAttributes<HTMLUListElement>) => (
6758
<ul
6859
className='mt-1 mb-1 space-y-1 pl-6 font-sans text-gray-800 dark:text-gray-200'
@@ -89,7 +80,6 @@ export default function MarkdownRenderer({
8980
</li>
9081
),
9182

92-
// Code blocks
9383
pre: ({ children }: HTMLAttributes<HTMLPreElement>) => {
9484
let codeProps: HTMLAttributes<HTMLElement> = {}
9585
let codeContent: ReactNode = children
@@ -120,7 +110,6 @@ export default function MarkdownRenderer({
120110
)
121111
},
122112

123-
// Inline code
124113
code: ({
125114
inline,
126115
className,
@@ -144,24 +133,20 @@ export default function MarkdownRenderer({
144133
)
145134
},
146135

147-
// Blockquotes
148136
blockquote: ({ children }: React.HTMLAttributes<HTMLQuoteElement>) => (
149137
<blockquote className='my-4 border-gray-300 border-l-4 py-1 pl-4 font-sans text-gray-700 italic dark:border-gray-600 dark:text-gray-300'>
150138
{children}
151139
</blockquote>
152140
),
153141

154-
// Horizontal rule
155142
hr: () => <hr className='my-8 border-gray-500/[.07] border-t dark:border-gray-400/[.07]' />,
156143

157-
// Links
158144
a: ({ href, children, ...props }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
159145
<LinkComponent href={href || '#'} {...props}>
160146
{children}
161147
</LinkComponent>
162148
),
163149

164-
// Tables
165150
table: ({ children }: React.TableHTMLAttributes<HTMLTableElement>) => (
166151
<div className='my-4 w-full overflow-x-auto'>
167152
<table className='min-w-full table-auto border border-gray-300 font-sans text-sm dark:border-gray-700'>
@@ -193,7 +178,6 @@ export default function MarkdownRenderer({
193178
</td>
194179
),
195180

196-
// Images
197181
img: ({ src, alt, ...props }: React.ImgHTMLAttributes<HTMLImageElement>) => (
198182
<img
199183
src={src}
@@ -203,15 +187,33 @@ export default function MarkdownRenderer({
203187
/>
204188
),
205189
}
190+
}
191+
192+
const DEFAULT_COMPONENTS = createCustomComponents(LinkWithPreview)
193+
194+
const MarkdownRenderer = memo(function MarkdownRenderer({
195+
content,
196+
customLinkComponent,
197+
}: {
198+
content: string
199+
customLinkComponent?: typeof LinkWithPreview
200+
}) {
201+
const components = useMemo(() => {
202+
if (!customLinkComponent) {
203+
return DEFAULT_COMPONENTS
204+
}
205+
return createCustomComponents(customLinkComponent)
206+
}, [customLinkComponent])
206207

207-
// Pre-process content to fix common issues
208208
const processedContent = content.trim()
209209

210210
return (
211211
<div className='space-y-4 break-words font-sans text-[#0D0D0D] text-base leading-relaxed dark:text-gray-100'>
212-
<ReactMarkdown remarkPlugins={[remarkGfm]} components={customComponents}>
212+
<ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={components}>
213213
{processedContent}
214214
</ReactMarkdown>
215215
</div>
216216
)
217-
}
217+
})
218+
219+
export default MarkdownRenderer

apps/sim/app/layout.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { generateBrandedMetadata, generateStructuredData } from '@/lib/branding/
77
import { PostHogProvider } from '@/app/_shell/providers/posthog-provider'
88
import '@/app/_styles/globals.css'
99
import { OneDollarStats } from '@/components/analytics/onedollarstats'
10-
import { isReactGrabEnabled } from '@/lib/core/config/feature-flags'
10+
import { isReactGrabEnabled, isReactScanEnabled } from '@/lib/core/config/feature-flags'
1111
import { HydrationErrorHandler } from '@/app/_shell/hydration-error-handler'
1212
import { QueryProvider } from '@/app/_shell/providers/query-provider'
1313
import { SessionProvider } from '@/app/_shell/providers/session-provider'
@@ -35,6 +35,13 @@ export default function RootLayout({ children }: { children: React.ReactNode })
3535
return (
3636
<html lang='en' suppressHydrationWarning>
3737
<head>
38+
{isReactScanEnabled && (
39+
<Script
40+
src='https://unpkg.com/react-scan/dist/auto.global.js'
41+
crossOrigin='anonymous'
42+
strategy='beforeInteractive'
43+
/>
44+
)}
3845
{isReactGrabEnabled && (
3946
<Script
4047
src='https://unpkg.com/react-grab/dist/index.global.js'

apps/sim/app/workspace/[workspaceId]/providers/workspace-permissions-provider.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import type React from 'react'
44
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
55
import { createLogger } from '@sim/logger'
66
import { useParams } from 'next/navigation'
7-
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
87
import { useUserPermissions, type WorkspaceUserPermissions } from '@/hooks/use-user-permissions'
98
import {
109
useWorkspacePermissions,
1110
type WorkspacePermissions,
1211
} from '@/hooks/use-workspace-permissions'
1312
import { useNotificationStore } from '@/stores/notifications'
13+
import { useOperationQueueStore } from '@/stores/operation-queue/store'
1414

1515
const logger = createLogger('WorkspacePermissionsProvider')
1616

@@ -64,8 +64,8 @@ export function WorkspacePermissionsProvider({ children }: WorkspacePermissionsP
6464
// Track whether we've already surfaced an offline notification to avoid duplicates
6565
const [hasShownOfflineNotification, setHasShownOfflineNotification] = useState(false)
6666

67-
// Get operation error state from collaborative workflow
68-
const { hasOperationError } = useCollaborativeWorkflow()
67+
// Get operation error state directly from the store (avoid full useCollaborativeWorkflow subscription)
68+
const hasOperationError = useOperationQueueStore((state) => state.hasOperationError)
6969

7070
const addNotification = useNotificationStore((state) => state.addNotification)
7171

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,16 @@ export const ActionBar = memo(
4949
collaborativeBatchToggleBlockHandles,
5050
} = useCollaborativeWorkflow()
5151
const { activeWorkflowId, setPendingSelection } = useWorkflowRegistry()
52-
const blocks = useWorkflowStore((state) => state.blocks)
53-
const subBlockStore = useSubBlockStore()
5452

5553
const handleDuplicateBlock = useCallback(() => {
54+
const blocks = useWorkflowStore.getState().blocks
5655
const sourceBlock = blocks[blockId]
5756
if (!sourceBlock) return
5857

5958
const newId = crypto.randomUUID()
6059
const newName = getUniqueBlockName(sourceBlock.name, blocks)
61-
const subBlockValues = subBlockStore.workflowValues[activeWorkflowId || '']?.[blockId] || {}
60+
const subBlockValues =
61+
useSubBlockStore.getState().workflowValues[activeWorkflowId || '']?.[blockId] || {}
6262

6363
const { block, subBlockValues: filteredValues } = prepareDuplicateBlockState({
6464
sourceBlock,
@@ -70,18 +70,8 @@ export const ActionBar = memo(
7070

7171
setPendingSelection([newId])
7272
collaborativeBatchAddBlocks([block], [], {}, {}, { [newId]: filteredValues })
73-
}, [
74-
blockId,
75-
blocks,
76-
activeWorkflowId,
77-
subBlockStore.workflowValues,
78-
collaborativeBatchAddBlocks,
79-
setPendingSelection,
80-
])
73+
}, [blockId, activeWorkflowId, collaborativeBatchAddBlocks, setPendingSelection])
8174

82-
/**
83-
* Optimized single store subscription for all block data
84-
*/
8575
const { isEnabled, horizontalHandles, parentId, parentType } = useWorkflowStore(
8676
useCallback(
8777
(state) => {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/copilot-message/components/markdown-renderer.tsx

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import ReactMarkdown from 'react-markdown'
66
import remarkGfm from 'remark-gfm'
77
import { Code, Tooltip } from '@/components/emcn'
88

9+
const REMARK_PLUGINS = [remarkGfm]
10+
911
/**
1012
* Recursively extracts text content from React elements
1113
* @param element - React node to extract text from
@@ -149,14 +151,12 @@ interface CopilotMarkdownRendererProps {
149151
* Tighter spacing compared to traditional prose for better chat UX
150152
*/
151153
const markdownComponents = {
152-
// Paragraphs - tight spacing, no margin on last
153154
p: ({ children }: React.HTMLAttributes<HTMLParagraphElement>) => (
154155
<p className='mb-1.5 font-base font-season text-[var(--text-primary)] text-sm leading-[1.4] last:mb-0 dark:font-[470]'>
155156
{children}
156157
</p>
157158
),
158159

159-
// Headings - minimal margins for chat context
160160
h1: ({ children }: React.HTMLAttributes<HTMLHeadingElement>) => (
161161
<h1 className='mt-2 mb-1 font-season font-semibold text-[var(--text-primary)] text-base first:mt-0'>
162162
{children}
@@ -178,7 +178,6 @@ const markdownComponents = {
178178
</h4>
179179
),
180180

181-
// Lists - compact spacing
182181
ul: ({ children }: React.HTMLAttributes<HTMLUListElement>) => (
183182
<ul
184183
className='my-1 space-y-0.5 pl-5 font-base font-season text-[var(--text-primary)] dark:font-[470]'
@@ -204,7 +203,6 @@ const markdownComponents = {
204203
</li>
205204
),
206205

207-
// Code blocks - handled by CodeBlock component
208206
pre: ({ children }: React.HTMLAttributes<HTMLPreElement>) => {
209207
let codeContent: React.ReactNode = children
210208
let language = 'code'
@@ -243,7 +241,6 @@ const markdownComponents = {
243241
return <CodeBlock code={actualCodeText} language={language} />
244242
},
245243

246-
// Inline code
247244
code: ({
248245
className,
249246
children,
@@ -257,7 +254,6 @@ const markdownComponents = {
257254
</code>
258255
),
259256

260-
// Text formatting
261257
strong: ({ children }: React.HTMLAttributes<HTMLElement>) => (
262258
<strong className='font-semibold text-[var(--text-primary)]'>{children}</strong>
263259
),
@@ -271,22 +267,18 @@ const markdownComponents = {
271267
<i className='text-[var(--text-primary)] italic'>{children}</i>
272268
),
273269

274-
// Blockquote - compact
275270
blockquote: ({ children }: React.HTMLAttributes<HTMLQuoteElement>) => (
276271
<blockquote className='my-1.5 border-[var(--border-1)] border-l-2 py-0.5 pl-3 font-season text-[var(--text-secondary)] text-sm italic'>
277272
{children}
278273
</blockquote>
279274
),
280275

281-
// Horizontal rule
282276
hr: () => <hr className='my-3 border-[var(--divider)] border-t' />,
283277

284-
// Links
285278
a: ({ href, children }: React.AnchorHTMLAttributes<HTMLAnchorElement>) => (
286279
<LinkWithPreview href={href || '#'}>{children}</LinkWithPreview>
287280
),
288281

289-
// Tables - compact
290282
table: ({ children }: React.TableHTMLAttributes<HTMLTableElement>) => (
291283
<div className='my-2 max-w-full overflow-x-auto'>
292284
<table className='min-w-full table-auto border border-[var(--border-1)] font-season text-xs'>
@@ -314,7 +306,6 @@ const markdownComponents = {
314306
</td>
315307
),
316308

317-
// Images
318309
img: ({ src, alt, ...props }: React.ImgHTMLAttributes<HTMLImageElement>) => (
319310
<img src={src} alt={alt || 'Image'} className='my-2 h-auto max-w-full rounded-md' {...props} />
320311
),
@@ -330,7 +321,7 @@ const markdownComponents = {
330321
function CopilotMarkdownRenderer({ content }: CopilotMarkdownRendererProps) {
331322
return (
332323
<div className='max-w-full break-words font-base font-season text-[var(--text-primary)] text-sm leading-[1.4] dark:font-[470] [&_*]:max-w-full [&_a]:break-all [&_code:not(pre_code)]:break-words [&_li]:break-words [&_p]:break-words'>
333-
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
324+
<ReactMarkdown remarkPlugins={REMARK_PLUGINS} components={markdownComponents}>
334325
{content}
335326
</ReactMarkdown>
336327
</div>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,2 @@
11
export { useCheckpointManagement } from './use-checkpoint-management'
22
export { useMessageEditing } from './use-message-editing'
3-
export { useMessageFeedback } from './use-message-feedback'
4-
export { useSuccessTimers } from './use-success-timers'

0 commit comments

Comments
 (0)