From 47525b211a37c2edcccda558d3f2b2300b5cc280 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Sun, 27 Sep 2026 12:09:45 +0200 Subject: [PATCH] perf: shrink the module graph that gates first paint in dev (#11373) * perf: shrink the module graph that gates first paint in dev * docs: drop the stale synchronous-icons claim on the import card * fix: replay search opened before its modal loads, guard lazy icons * fix: only intercept search before load where the modal mounts * perf: mount app-shell modals on first open and keep monaco off the shell * perf: load the icon map on first read, not at module evaluation * fix: report stale chunks with a reload toast, guard the home page against monaco --- frontend/src/lib/components/Dev.svelte | 2 +- .../src/lib/components/DisplayResult.svelte | 15 +- .../src/lib/components/FilterSearchbar.svelte | 30 +-- .../lib/components/IconedResourceType.svelte | 2 +- .../lib/components/ImportProjectCard.svelte | 4 +- .../src/lib/components/ResourcePicker.svelte | 2 +- frontend/src/lib/components/RunsPage.svelte | 49 ++-- .../lib/components/ToggleHubWorkspace.svelte | 2 +- .../components/ToggleHubWorkspaceQuick.svelte | 2 +- .../copilot/chat/AIChatModelSettings.svelte | 42 ++-- .../copilot/chat/AiChatLayout.svelte | 6 +- .../chat/CreatedResourceActionDrawers.svelte | 215 ++---------------- .../CreatedResourceActionDrawersInner.svelte | 192 ++++++++++++++++ .../src/lib/components/copilot/chat/shared.ts | 2 +- frontend/src/lib/components/copilot/shared.ts | 2 +- .../flows/pickers/PickHubScript.svelte | 6 +- .../flows/pickers/PickHubScriptQuick.svelte | 6 +- .../lib/components/graph/FlowGraphV2.svelte | 6 +- .../src/lib/components/home/ItemsList.svelte | 14 +- .../lib/components/home/ListFilters.svelte | 6 +- .../components/home/ListFiltersQuick.svelte | 2 +- .../lib/components/icons/appIcon.svelte.ts | 32 +++ .../components/resources/ResourcesList.svelte | 35 +-- .../lib/components/search/RunsSearch.svelte | 12 +- .../sidebar/FinishAccountSetup.svelte | 4 +- .../components/sidebar/MultiplayerMenu.svelte | 2 +- .../triggers/AddTriggersButton.svelte | 2 +- .../components/triggers/CaptureTable.svelte | 4 +- .../triggers/schedules/ScheduleEditor.svelte | 13 +- .../WorkspaceIntegrations.svelte | 3 +- frontend/src/lib/hubProject.test.ts | 24 +- frontend/src/lib/hubProject.ts | 2 +- .../src/routes/(root)/(logged)/+layout.svelte | 89 ++++++-- .../[service_name]/+page.svelte | 4 +- .../(logged)/user/(user)/login/+page.svelte | 2 +- .../user/(user)/workspaces/+page.svelte | 2 +- .../workspace_settings/checkout/+page.svelte | 2 +- frontend/src/routes/(root)/+layout.svelte | 28 ++- .../routes/kitchen_sink/login/+page.svelte | 2 +- frontend/vite.config.js | 97 ++++++-- 40 files changed, 614 insertions(+), 352 deletions(-) create mode 100644 frontend/src/lib/components/copilot/chat/CreatedResourceActionDrawersInner.svelte create mode 100644 frontend/src/lib/components/icons/appIcon.svelte.ts diff --git a/frontend/src/lib/components/Dev.svelte b/frontend/src/lib/components/Dev.svelte index 1bf9e7fde3..750524457e 100644 --- a/frontend/src/lib/components/Dev.svelte +++ b/frontend/src/lib/components/Dev.svelte @@ -4,7 +4,7 @@ import { argsToJsonPayload } from '$lib/schema' import JobLoader from '$lib/components/JobLoader.svelte' import { Button } from '$lib/components/common' - import { WindmillIcon } from '$lib/components/icons' + import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte' import LogPanel from '$lib/components/scriptEditor/LogPanel.svelte' import { type CompletedJob, diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index d0de2026cf..a49f09bb02 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -22,7 +22,6 @@ Database, Loader2 } from 'lucide-svelte' - import DucklakeResultPreview from './assets/AssetGraph/DucklakeResultPreview.svelte' import DataTestsResult from './DataTestsResult.svelte' import Portal from '$lib/components/Portal.svelte' import DisplayResultControlBar from './DisplayResultControlBar.svelte' @@ -1105,11 +1104,15 @@ /> {#if showMaterializedPreview}
- + + {#await import('./assets/AssetGraph/DucklakeResultPreview.svelte') then DucklakeResultPreview} + + {/await}
{/if} diff --git a/frontend/src/lib/components/FilterSearchbar.svelte b/frontend/src/lib/components/FilterSearchbar.svelte index 30adb56c7c..b4bc4471a2 100644 --- a/frontend/src/lib/components/FilterSearchbar.svelte +++ b/frontend/src/lib/components/FilterSearchbar.svelte @@ -307,7 +307,6 @@ import { MinusIcon, SearchIcon } from 'lucide-svelte' import { assignObjInPlace, clone } from '$lib/utils' import GenericDropdown from './select/GenericDropdown.svelte' - import SimpleEditor from './SimpleEditor.svelte' import TaggedTextInput from './TaggedTextInput.svelte' import { DebouncedTempValue, useTransformedSyncedValue } from '$lib/svelte5Utils.svelte' import { untrack } from 'svelte' @@ -885,20 +884,23 @@ {:else if filter.type === 'string' && filter.format === 'json'}
- String(value[currentTag!] ?? ''), - (v) => { - setValueForCurrentTag(v ?? '') - taggedTextInput?.preventCursorMoveOnNextSync() + + {#await import('./SimpleEditor.svelte') then SimpleEditor} + String(value[currentTag!] ?? ''), + (v) => { + setValueForCurrentTag(v ?? '') + taggedTextInput?.preventCursorMoveOnNextSync() + } } - } - class="border border-border-light rounded min-h-[4rem]" - /> + class="border border-border-light rounded min-h-[4rem]" + /> + {/await}
{:else if filter.type === 'string'} {#if menuItems.length} diff --git a/frontend/src/lib/components/IconedResourceType.svelte b/frontend/src/lib/components/IconedResourceType.svelte index 996cfb2a79..94e08293f2 100644 --- a/frontend/src/lib/components/IconedResourceType.svelte +++ b/frontend/src/lib/components/IconedResourceType.svelte @@ -1,6 +1,6 @@ - - drawer?.closeDrawer()}> - {#if activeDrawer} - {#key activeDrawer.key} - {#await activeDrawer.promise} -
- -
- {:then Module} - {@const Editor = Module.default as EditorComponent} - - {/await} - {/key} - {/if} -
-
- - - +{#if inner} + {#await inner then Inner} + + {/await} +{/if} diff --git a/frontend/src/lib/components/copilot/chat/CreatedResourceActionDrawersInner.svelte b/frontend/src/lib/components/copilot/chat/CreatedResourceActionDrawersInner.svelte new file mode 100644 index 0000000000..9dd8fe643c --- /dev/null +++ b/frontend/src/lib/components/copilot/chat/CreatedResourceActionDrawersInner.svelte @@ -0,0 +1,192 @@ + + + + drawer?.closeDrawer()}> + {#if activeDrawer} + {#key activeDrawer.key} + {#await activeDrawer.promise} +
+ +
+ {:then Module} + {@const Editor = Module.default as EditorComponent} + + {/await} + {/key} + {/if} +
+
+ + + diff --git a/frontend/src/lib/components/copilot/chat/shared.ts b/frontend/src/lib/components/copilot/chat/shared.ts index 1e486c7d41..6df8b68518 100644 --- a/frontend/src/lib/components/copilot/chat/shared.ts +++ b/frontend/src/lib/components/copilot/chat/shared.ts @@ -60,7 +60,7 @@ import { logFeatureUsage, logHubScriptPick } from '$lib/utils/featureUsage' import { forLater } from '$lib/forLater' import { scriptLangToEditorLang } from '$lib/scripts' import { getCurrentModel } from '$lib/aiStore' -import { type editor as meditor } from 'monaco-editor' +import type { editor as meditor } from 'monaco-editor' import { pendingFolderInstructions, type FolderInstructionsContext } from './folderInstructions' // Prettify function for code arguments - extracts and formats code from JSON diff --git a/frontend/src/lib/components/copilot/shared.ts b/frontend/src/lib/components/copilot/shared.ts index ed37052298..1cdfc239ad 100644 --- a/frontend/src/lib/components/copilot/shared.ts +++ b/frontend/src/lib/components/copilot/shared.ts @@ -1,5 +1,5 @@ import { createLongHash } from '$lib/editorLangUtils' -import { type editor as meditor } from 'monaco-editor' +import type { editor as meditor } from 'monaco-editor' export type VisualChange = | { diff --git a/frontend/src/lib/components/flows/pickers/PickHubScript.svelte b/frontend/src/lib/components/flows/pickers/PickHubScript.svelte index 2e63266a58..5d3de9150b 100644 --- a/frontend/src/lib/components/flows/pickers/PickHubScript.svelte +++ b/frontend/src/lib/components/flows/pickers/PickHubScript.svelte @@ -3,7 +3,7 @@ import { Alert, Badge, ButtonType, Skeleton } from '$lib/components/common' import { capitalize } from '$lib/utils' import NoItemFound from '$lib/components/home/NoItemFound.svelte' - import { APP_TO_ICON_COMPONENT } from '$lib/components/icons' + import { appIconMap } from '$lib/components/icons/appIcon.svelte' import { listHubIntegrationsShared } from '$lib/components/displayNameLoaders' import ListFilters from '$lib/components/home/ListFilters.svelte' import { ScriptService, type HubScriptKind } from '$lib/gen' @@ -205,8 +205,8 @@ >
- {#if item['app'] in APP_TO_ICON_COMPONENT} - {@const SvelteComponent = APP_TO_ICON_COMPONENT[item['app']]} + {#if appIconMap()?.[item['app']]} + {@const SvelteComponent = appIconMap()![item['app']]} {/if}
diff --git a/frontend/src/lib/components/flows/pickers/PickHubScriptQuick.svelte b/frontend/src/lib/components/flows/pickers/PickHubScriptQuick.svelte index 6648c622c0..e1cfa1d972 100644 --- a/frontend/src/lib/components/flows/pickers/PickHubScriptQuick.svelte +++ b/frontend/src/lib/components/flows/pickers/PickHubScriptQuick.svelte @@ -36,7 +36,7 @@ import { createEventDispatcher, getContext, untrack } from 'svelte' import { Skeleton } from '$lib/components/common' import { classNames, createCache } from '$lib/utils' - import { APP_TO_ICON_COMPONENT } from '$lib/components/icons' + import { appIconMap } from '$lib/components/icons/appIcon.svelte' import { listHubIntegrationsShared } from '$lib/components/displayNameLoaders' import { ScriptService, type HubScriptKind } from '$lib/gen' import { Circle, ExternalLink } from 'lucide-svelte' @@ -253,8 +253,8 @@ onClick={() => handlePickScript(item)} >
- {#if item['app'] in APP_TO_ICON_COMPONENT} - {@const SvelteComponent = APP_TO_ICON_COMPONENT[item['app']]} + {#if appIconMap()?.[item['app']]} + {@const SvelteComponent = appIconMap()![item['app']]} {:else}
diff --git a/frontend/src/lib/components/graph/FlowGraphV2.svelte b/frontend/src/lib/components/graph/FlowGraphV2.svelte index 3c870832ee..0f833084c7 100644 --- a/frontend/src/lib/components/graph/FlowGraphV2.svelte +++ b/frontend/src/lib/components/graph/FlowGraphV2.svelte @@ -52,7 +52,6 @@ import TriggersNode from './renderers/nodes/TriggersNode.svelte' import { Alert, Drawer } from '../common' import Button from '../common/button/Button.svelte' - import FlowYamlEditor from '../flows/header/FlowYamlEditor.svelte' import BranchOneEndNode from './renderers/nodes/branchOneEndNode.svelte' import type { TriggerContext } from '../triggers' import SubflowBound from './renderers/nodes/SubflowBound.svelte' @@ -1296,7 +1295,10 @@ {#if insertable} - + + {#await import('../flows/header/FlowYamlEditor.svelte') then FlowYamlEditor} + + {/await} {/if} {#if canUseDiffDrawer} diff --git a/frontend/src/lib/components/home/ItemsList.svelte b/frontend/src/lib/components/home/ItemsList.svelte index f86ec9d5bf..1d9edc683b 100644 --- a/frontend/src/lib/components/home/ItemsList.svelte +++ b/frontend/src/lib/components/home/ItemsList.svelte @@ -41,7 +41,6 @@ import NoItemFound from './NoItemFound.svelte' import WorkspaceEmptyState from './WorkspaceEmptyState.svelte' import HubProjectPickerModal from './HubProjectPickerModal.svelte' - import ImportProjectModal from './ImportProjectModal.svelte' import type { HubProjectPick } from '$lib/hubProject' import ListFilters from './ListFilters.svelte' import ToggleButtonGroup from '../common/toggleButton-v2/ToggleButtonGroup.svelte' @@ -1009,6 +1008,11 @@ // the create menu's Import section open the same dialog, and mounting one per entry point // would put two of them on the page at once while the workspace is still empty. let hubPick = $state(undefined) + // Sticky, so the import modal mounts on the first pick and then stays for its close animation. + let hubImportRequested = $state(false) + $effect(() => { + if (hubPick) hubImportRequested = true + }) let hubPickerOpen = $state(false) /** @@ -2077,7 +2081,13 @@ hubPick = project }} /> - (hubPick = undefined)} {onImported} /> + +{#if hubImportRequested} + {#await import('./ImportProjectModal.svelte') then ImportProjectModal} + (hubPick = undefined)} {onImported} /> + {/await} +{/if}