diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index eaeeb096ba..ad4312efbf 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -31,7 +31,8 @@ FileClock, Sun, Moon, - SunMoon + SunMoon, + Zap } from 'lucide-svelte' import { createEventDispatcher, getContext } from 'svelte' import { Pane, Splitpanes } from 'svelte-splitpanes' @@ -92,6 +93,7 @@ import { isCloudHosted } from '$lib/cloud' import { base } from '$lib/base' import ClipboardPanel from '$lib/components/details/ClipboardPanel.svelte' + import LazyModePanel from './contextPanel/LazyModePanel.svelte' async function hash(message) { try { @@ -175,6 +177,7 @@ let inputsDrawerOpen = fromHub let historyBrowserDrawerOpen = false let debugAppDrawerOpen = false + let lazyDrawerOpen = false let deploymentMsg: string | undefined = undefined function closeSaveDrawer() { @@ -871,6 +874,13 @@ action: () => { debugAppDrawerOpen = true } + }, + { + displayName: 'Lazy mode', + icon: Zap, + action: () => { + lazyDrawerOpen = true + } } ] @@ -1267,6 +1277,11 @@ + + (lazyDrawerOpen = false)}> + + + import { getContext, onMount } from 'svelte' - import type { AppEditorContext, AppViewerContext } from '../types' - import { allItems } from '../utils' + import type { App, AppEditorContext, AppViewerContext } from '../types' + import { allItems, BG_PREFIX } from '../utils' import RecomputeAllButton from './RecomputeAllButton.svelte' const { runnableComponents, app, initialized, recomputeAllContext } = @@ -13,10 +13,21 @@ let firstLoad = false let progressTimer: NodeJS.Timeout | undefined = undefined - $: !firstLoad && - $initialized.initializedComponents?.length == - allItems($app.grid, $app.subgrids).length + ($app.hiddenInlineScripts?.length ?? 0) && - refresh() + $: !firstLoad && canInitializeAll($initialized?.initializedComponents, $app) && refresh() + + function canInitializeAll(initialized: string[] | undefined, app: App) { + if (app.lazyInitRequire == undefined) { + return ( + initialized?.length == + allItems(app.grid, app.subgrids).length + (app.hiddenInlineScripts?.length ?? 0) + ) + } else { + return ( + app.hiddenInlineScripts?.every((x, i) => initialized?.includes(BG_PREFIX + i)) && + app.lazyInitRequire?.every((x) => initialized?.includes(x)) + ) + } + } $: $recomputeAllContext.componentNumber = Object.values($runnableComponents).filter((x) => x.autoRefresh).length ?? 0 diff --git a/frontend/src/lib/components/apps/editor/RecomputeAllWrapper.svelte b/frontend/src/lib/components/apps/editor/RecomputeAllWrapper.svelte index 83c1fef5be..46a464d71b 100644 --- a/frontend/src/lib/components/apps/editor/RecomputeAllWrapper.svelte +++ b/frontend/src/lib/components/apps/editor/RecomputeAllWrapper.svelte @@ -1,8 +1,6 @@
-{:else} +{:else if $app.lazyInitRequire == undefined} {#each $app?.subgrids?.[subGridId] ?? [] as item} {/each} diff --git a/frontend/src/lib/components/apps/editor/contextPanel/LazyModePanel.svelte b/frontend/src/lib/components/apps/editor/contextPanel/LazyModePanel.svelte new file mode 100644 index 0000000000..0ae456e7f8 --- /dev/null +++ b/frontend/src/lib/components/apps/editor/contextPanel/LazyModePanel.svelte @@ -0,0 +1,50 @@ + + +
+ + Lazy mode is a feature that allows you to lazy render components which is ideal for apps with + many components where most are not directly visible to the user. +
+ When lazy mode is enabled, components are not rendered until they are needed. This can significantly + improve the performance of your app, especially on mobile devices. +
+ You can enable lazy mode below, but you will need to declare the list of components whose initialization + is expected to see initialized before the initial refresh of the app happens. +
+ + { + $app.lazyInitRequire = e.detail ? [] : undefined + code = JSON.stringify($app.lazyInitRequire) + }} + options={{ + right: 'Lazy mode' + }} + /> + +
+ {#if $app.lazyInitRequire} + + + {'e.g: ["a", "b"]'}, no need to put background runnables ids + + {:else} + Without lazy mode, all components' initialization will be waited on the initial refresh. + {/if} +
+
diff --git a/frontend/src/lib/components/apps/types.ts b/frontend/src/lib/components/apps/types.ts index 7debc557f1..c20fe5e561 100644 --- a/frontend/src/lib/components/apps/types.ts +++ b/frontend/src/lib/components/apps/types.ts @@ -139,13 +139,13 @@ export type HiddenRunnable = { export type AppTheme = | { - type: 'path' - path: string - } + type: 'path' + path: string + } | { - type: 'inlined' - css: string - } + type: 'inlined' + css: string + } export type App = { grid: GridItem[] @@ -162,6 +162,7 @@ export type App = { css?: Partial>> subgrids?: Record theme: AppTheme | undefined + lazyInitRequire?: string[] | undefined hideLegacyTopBar?: boolean | undefined mobileViewOnSmallerScreens?: boolean | undefined version?: number