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}