Optimise builder preview speed and performance and fix components not updating when changing props

This commit is contained in:
Andrew Kingston 2020-11-30 12:11:50 +00:00
parent cb626d685b
commit 3ee9fee10c
5 changed files with 40 additions and 16 deletions

View File

@ -22,27 +22,37 @@
? screenPlaceholder ? screenPlaceholder
: $store.currentPreviewItem : $store.currentPreviewItem
$: selectedComponentId = $store.currentComponentInfo?._id ?? "" $: selectedComponentId = $store.currentComponentInfo?._id ?? ""
$: previewData = {
page, // Saving pages and screens to the DB causes them to have _revs.
screen, // These revisions change every time a save happens and causes
selectedComponentId, // these reactive statements to fire, even though the actual
} // definition hasn't changed.
// By deleting all _rev properties we can avoid this and increase
// performance.
$: json = JSON.stringify({ page, screen, selectedComponentId })
$: strippedJson = json.replaceAll(/"_rev":\s*"[^"]+"/g, `"_rev":""`)
// Update the iframe with the builder info to render the correct preview // Update the iframe with the builder info to render the correct preview
const refreshContent = () => { const refreshContent = message => {
if (iframe) { if (iframe) {
iframe.contentWindow.postMessage(JSON.stringify(previewData)) iframe.contentWindow.postMessage(message)
} }
} }
// Refresh the preview when required // Refresh the preview when required
$: refreshContent(previewData) $: refreshContent(strippedJson)
// Initialise the app when mounted // Initialise the app when mounted
onMount(() => { onMount(() => {
iframe.contentWindow.addEventListener("bb-ready", refreshContent, { iframe.contentWindow.addEventListener(
once: true, "bb-ready",
}) () => {
refreshContent(strippedJson)
},
{
once: true,
}
)
}) })
</script> </script>

View File

@ -32,9 +32,11 @@ export default `<html>
selectedComponentStyle.appendChild(document.createTextNode(selectedCss)) selectedComponentStyle.appendChild(document.createTextNode(selectedCss))
// Set some flags so the app knows we're in the builder // Set some flags so the app knows we're in the builder
window["##BUDIBASE_IN_BUILDER##"] = true; window["##BUDIBASE_IN_BUILDER##"] = true
window["##BUDIBASE_PREVIEW_PAGE##"] = page; window["##BUDIBASE_PREVIEW_PAGE##"] = page
window["##BUDIBASE_PREVIEW_SCREEN##"] = screen; window["##BUDIBASE_PREVIEW_SCREEN##"] = screen
window["##BUDIBASE_SELECTED_COMPONENT_ID##"] = selectedComponentId
window["##BUDIBASE_PREVIEW_ID##"] = Math.random()
// Initialise app // Initialise app
if (window.loadBudibase) { if (window.loadBudibase) {

View File

@ -4,7 +4,7 @@
import * as ComponentLibrary from "@budibase/standard-components" import * as ComponentLibrary from "@budibase/standard-components"
import Router from "./Router.svelte" import Router from "./Router.svelte"
import { enrichProps } from "../utils/componentProps" import { enrichProps } from "../utils/componentProps"
import { bindingStore } from "../store" import { bindingStore, builderStore } from "../store"
export let definition = {} export let definition = {}
@ -32,12 +32,20 @@
const name = split?.[split.length - 1] const name = split?.[split.length - 1]
return name === "screenslot" ? Router : ComponentLibrary[name] return name === "screenslot" ? Router : ComponentLibrary[name]
} }
// Returns a unique key to let svelte know when to remount components.
// If a component is selected we want to remount it every time any props
// change.
const getChildKey = childId => {
const selected = childId === $builderStore.selectedComponentId
return selected ? `${childId}-${$builderStore.previewId}` : childId
}
</script> </script>
{#if constructor} {#if constructor}
<svelte:component this={constructor} {...enrichedProps}> <svelte:component this={constructor} {...enrichedProps}>
{#if children && children.length} {#if children && children.length}
{#each children as child (child._id)} {#each children as child (getChildKey(child._id))}
<svelte:self definition={child} /> <svelte:self definition={child} />
{/each} {/each}
{/if} {/if}

View File

@ -9,6 +9,8 @@ const loadBudibase = () => {
inBuilder: !!window["##BUDIBASE_IN_BUILDER##"], inBuilder: !!window["##BUDIBASE_IN_BUILDER##"],
page: window["##BUDIBASE_PREVIEW_PAGE##"], page: window["##BUDIBASE_PREVIEW_PAGE##"],
screen: window["##BUDIBASE_PREVIEW_SCREEN##"], screen: window["##BUDIBASE_PREVIEW_SCREEN##"],
selectedComponentId: window["##BUDIBASE_SELECTED_COMPONENT_ID##"],
previewId: window["##BUDIBASE_PREVIEW_ID##"],
}) })
// Create app if one hasn't been created yet // Create app if one hasn't been created yet

View File

@ -5,6 +5,8 @@ const createBuilderStore = () => {
inBuilder: false, inBuilder: false,
page: null, page: null,
screen: null, screen: null,
selectedComponentId: null,
previewId: null,
} }
return writable(initialState) return writable(initialState)
} }