diff --git a/.claude/rules/sim-imports.md b/.claude/rules/sim-imports.md index 74bf556db4d..0449d96e11e 100644 --- a/.claude/rules/sim-imports.md +++ b/.claude/rules/sim-imports.md @@ -31,6 +31,20 @@ import { Dashboard, Sidebar } from '@/app/workspace/[workspaceId]/logs/component import { Dashboard } from '@/app/workspace/[workspaceId]/logs/components/dashboard/dashboard' ``` +## Code-splitting through barrels + +When you `lazy(() => import(...))` a component to keep it out of a route's initial bundle, import the **deep module path** (`./components/foo/foo`), never the barrel — and **delete the now-dead barrel re-export** of that component. This app has no `"sideEffects": false` in `apps/sim/package.json`, so when any sibling still imports that barrel, webpack can conservatively keep the barrel's re-export edge to the heavy module. A leftover `export { Foo } from './foo'` line can therefore drag `Foo` (and its transitive deps) back into the initial chunk and silently defeat the split. Removing the dead re-export is the guaranteed fix; verify with a production bundle diff, not by eyeballing the `lazy()` call. + +```typescript +// ✓ Good — deep lazy import + no barrel edge left behind +const MothershipView = lazy(() => + import('./components/mothership-view/mothership-view').then((m) => ({ default: m.MothershipView })) +) +// (and remove `export { MothershipView } from './mothership-view'` from components/index.ts) +``` + +Wrap the lazy component in a **local ``** so its suspension resolves at the nearest boundary instead of bubbling to the page-level fallback (which would flash the whole route). `React.lazy(memo(forwardRef(...)))` forwards a DOM `ref` correctly in React 19 — but during the fallback window `ref.current` is `null`, so every consumer must guard it (`if (!el) return` / `el?.`). + ## No Re-exports Do not re-export from non-barrel files. Import directly from the source. diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/index.ts b/apps/sim/app/workspace/[workspaceId]/home/components/index.ts index 799c9f2c2fd..8425c127a6e 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/index.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/index.ts @@ -11,7 +11,6 @@ export { MothershipResourcesProvider, useMothershipResources, } from './mothership-resources-context' -export { MothershipView } from './mothership-view' export { QueuedMessages } from './queued-messages' export { SuggestedActions } from './suggested-actions' export { UserInput, type UserInputHandle } from './user-input' diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx index d716c1d32ba..b3d9cb78edd 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/prompt-editor/prompt-editor.tsx @@ -122,6 +122,11 @@ export function PromptEditor({ return {displayText} } + const contextByLabel = new Map() + for (const c of contexts) { + if (!contextByLabel.has(c.label)) contextByLabel.set(c.label, c) + } + const elements: React.ReactNode[] = [] let lastIndex = 0 for (let i = 0; i < ranges.length; i++) { @@ -133,7 +138,7 @@ export function PromptEditor({ } const mentionLabel = stripMentionTrigger(range.token) - const matchingCtx = contexts.find((c) => c.label === mentionLabel) + const matchingCtx = contextByLabel.get(mentionLabel) const mentionIconNode = matchingCtx ? ( + import('./components/mothership-view/mothership-view').then((m) => ({ + default: m.MothershipView, + })) +) + interface HomeProps { chatId?: string userName?: string @@ -491,18 +503,20 @@ export function Home({ chatId, userName, userId }: HomeProps) { reorderResources={reorderResources} collapseResource={collapseResource} > - + + + {isResourceCollapsed && (