Skip to content

Commit cd4041e

Browse files
authored
fix: Speedup resize, part 1 (#4543)
## Description Removes rerender of the whole builder during resize. Still some debounced resize of style panel etc exists. But will investigate in following PR ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 0000) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
1 parent a3d9ac4 commit cd4041e

File tree

5 files changed

+83
-88
lines changed

5 files changed

+83
-88
lines changed

apps/builder/app/builder/builder.tsx

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState, type ReactNode } from "react";
1+
import { useEffect, useMemo, useState, type ReactNode } from "react";
22
import { useStore } from "@nanostores/react";
33
import { TooltipProvider } from "@radix-ui/react-tooltip";
44
import { usePublish, $publisher } from "~/shared/pubsub";
@@ -20,7 +20,6 @@ import { Footer } from "./features/footer";
2020
import {
2121
CanvasIframe,
2222
CanvasToolsContainer,
23-
useReadCanvasRect,
2423
Workspace,
2524
} from "./features/workspace";
2625
import {
@@ -300,19 +299,20 @@ export const Builder = ({
300299
const isDesignMode = useStore($isDesignMode);
301300
const isContentMode = useStore($isContentMode);
302301

303-
const { onRef: onRefReadCanvas, onTransitionEnd } = useReadCanvasRect();
304-
305302
useSetWindowTitle();
306303

307-
const iframeRefCallback = mergeRefs((element: HTMLIFrameElement | null) => {
308-
if (element?.contentWindow) {
309-
// added to iframe window and stored in local variable right away to prevent
310-
// overriding in emebedded scripts on canvas
311-
element.contentWindow.__webstudioSharedSyncEmitter__ =
312-
builderClient.emitter;
313-
}
314-
onRefReadCanvas(element);
315-
}, publishRef);
304+
const iframeRefCallback = useMemo(
305+
() =>
306+
mergeRefs((element: HTMLIFrameElement | null) => {
307+
if (element?.contentWindow) {
308+
// added to iframe window and stored in local variable right away to prevent
309+
// overriding in emebedded scripts on canvas
310+
element.contentWindow.__webstudioSharedSyncEmitter__ =
311+
builderClient.emitter;
312+
}
313+
}, publishRef),
314+
[publishRef]
315+
);
316316

317317
const { navigatorLayout } = useStore($settings);
318318
const dataLoadingState = useStore($dataLoadingState);
@@ -369,7 +369,7 @@ export const Builder = ({
369369
>
370370
<ProjectSettings />
371371
<Main>
372-
<Workspace onTransitionEnd={onTransitionEnd}>
372+
<Workspace>
373373
{dataLoadingState === "loaded" && (
374374
<CanvasIframe
375375
ref={iframeRefCallback}

apps/builder/app/builder/features/workspace/canvas-iframe.tsx

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
import { forwardRef } from "react";
1+
import { forwardRef, useMemo, useRef, type RefObject } from "react";
22
import {
33
css,
44
canvasPointerEventsPropertyName,
55
} from "@webstudio-is/design-system";
66
import { useUnmount } from "~/shared/hook-utils/use-mount";
77
import { $canvasIframeState } from "~/shared/nano-states";
8+
import { useCallback, useEffect, useState } from "react";
9+
import {
10+
$scale,
11+
$canvasWidth,
12+
$canvasRect,
13+
} from "~/builder/shared/nano-states";
14+
import { useWindowResizeDebounced } from "~/shared/dom-hooks";
15+
import { mergeRefs } from "@react-aria/utils";
816

917
const iframeStyle = css({
1018
border: "none",
@@ -16,20 +24,72 @@ const iframeStyle = css({
1624

1725
type CanvasIframeProps = JSX.IntrinsicElements["iframe"];
1826

27+
const CanvasRectUpdater = ({
28+
iframeRef,
29+
}: {
30+
iframeRef: RefObject<HTMLIFrameElement>;
31+
}) => {
32+
const [updateCallback, setUpdateCallback] = useState<
33+
undefined | (() => void)
34+
>(undefined);
35+
36+
useEffect(() => {
37+
updateCallback?.();
38+
}, [updateCallback]);
39+
40+
const updateRect = useCallback(() => {
41+
// create new function to trigger effect
42+
const task = () => {
43+
if (iframeRef.current === null) {
44+
return;
45+
}
46+
47+
const rect = iframeRef.current.getBoundingClientRect();
48+
$canvasRect.set(rect);
49+
};
50+
51+
setUpdateCallback(() => task);
52+
}, [iframeRef]);
53+
54+
useEffect(() => {
55+
updateRect();
56+
const $scaleUnsubscribe = $scale.listen(updateRect);
57+
const $canvasWidthUnsubscribe = $canvasWidth.listen(updateRect);
58+
59+
return () => {
60+
$scaleUnsubscribe();
61+
$canvasWidthUnsubscribe();
62+
};
63+
}, [updateRect]);
64+
65+
useWindowResizeDebounced(() => {
66+
updateRect();
67+
});
68+
69+
return null;
70+
};
71+
1972
export const CanvasIframe = forwardRef<HTMLIFrameElement, CanvasIframeProps>(
2073
(props, ref) => {
74+
const iframeRef = useRef<HTMLIFrameElement | null>(null);
75+
76+
const merrgedRef = useMemo(() => mergeRefs(ref, iframeRef), [ref]);
77+
2178
useUnmount(() => {
2279
// Unmount does't work inside iframe.
2380
$canvasIframeState.set("idle");
2481
});
2582

2683
return (
27-
<iframe
28-
{...props}
29-
ref={ref}
30-
className={iframeStyle()}
31-
credentialless="true"
32-
/>
84+
<>
85+
<iframe
86+
{...props}
87+
ref={merrgedRef}
88+
className={iframeStyle()}
89+
credentialless="true"
90+
/>
91+
<CanvasRectUpdater iframeRef={iframeRef} />
92+
</>
3393
);
3494
}
3595
);
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from "./workspace";
2-
export * from "./use-read-canvas-rect";
32
export * from "./canvas-iframe";

apps/builder/app/builder/features/workspace/use-read-canvas-rect.ts

Lines changed: 0 additions & 59 deletions
This file was deleted.

apps/builder/app/builder/features/workspace/workspace.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,9 @@ const useOutlineStyle = () => {
9292

9393
type WorkspaceProps = {
9494
children: ReactNode;
95-
onTransitionEnd: () => void;
9695
};
9796

98-
export const Workspace = ({ children, onTransitionEnd }: WorkspaceProps) => {
97+
export const Workspace = ({ children }: WorkspaceProps) => {
9998
const canvasStyle = useCanvasStyle();
10099
const workspaceRef = useMeasureWorkspace();
101100
useSetCanvasWidth();
@@ -112,11 +111,7 @@ export const Workspace = ({ children, onTransitionEnd }: WorkspaceProps) => {
112111
onClick={handleWorkspaceClick}
113112
ref={workspaceRef}
114113
>
115-
<div
116-
className={canvasContainerStyle()}
117-
style={canvasStyle}
118-
onTransitionEnd={onTransitionEnd}
119-
>
114+
<div className={canvasContainerStyle()} style={canvasStyle}>
120115
{children}
121116
</div>
122117
<div

0 commit comments

Comments
 (0)