Fix front component worker re-creation on every render (#19245)
- `frontComponentHostCommunicationApi` gets a new object reference on every render, causing the `useMemo`/`useEffect` in `FrontComponentWorkerEffect` to tear down and re-create the web worker each time. - Decouple the host API lifecycle from the worker lifecycle by moving thread.exports updates into a dedicated `FrontComponentUpdateHostCommunicationApiEffect` that mutates the thread's exports object in place via Object.assign. - Rename `FrontComponentHostCommunicationApiEffect` to `FrontComponentInitializeHostCommunicationApiEffect` for clarity. ## Before https://github.com/user-attachments/assets/6f3a5c14-2ae7-4317-82b5-1625abb4143e ## After https://github.com/user-attachments/assets/1059d6cd-e02c-4477-b3e8-8e965a716434
This commit is contained in:
+9
-4
@@ -1,6 +1,7 @@
|
||||
import { FrontComponentErrorEffect } from '@/remote/components/FrontComponentErrorEffect';
|
||||
import { FrontComponentHostCommunicationApiEffect } from '@/remote/components/FrontComponentHostCommunicationApiEffect';
|
||||
import { FrontComponentInitializeHostCommunicationApiEffect } from '@/remote/components/FrontComponentInitializeHostCommunicationApiEffect';
|
||||
import { FrontComponentUpdateContextEffect } from '@/remote/components/FrontComponentUpdateContextEffect';
|
||||
import { FrontComponentUpdateHostCommunicationApiEffect } from '@/remote/components/FrontComponentUpdateHostCommunicationApiEffect';
|
||||
import { type FrontComponentHostCommunicationApi } from '@/types/FrontComponentHostCommunicationApi';
|
||||
import { type SdkClientUrls } from '@/types/HostToWorkerRenderContext';
|
||||
import { type WorkerExports } from '@/types/WorkerExports';
|
||||
@@ -55,7 +56,6 @@ export const FrontComponentRenderer = ({
|
||||
apiUrl={apiUrl}
|
||||
sdkClientUrls={sdkClientUrls}
|
||||
frontComponentId={executionContext.frontComponentId}
|
||||
frontComponentHostCommunicationApi={frontComponentHostCommunicationApi}
|
||||
setReceiver={setReceiver}
|
||||
setThread={setThread}
|
||||
setError={setError}
|
||||
@@ -63,7 +63,6 @@ export const FrontComponentRenderer = ({
|
||||
);
|
||||
}, [
|
||||
componentUrl,
|
||||
frontComponentHostCommunicationApi,
|
||||
setError,
|
||||
setReceiver,
|
||||
setThread,
|
||||
@@ -102,7 +101,13 @@ export const FrontComponentRenderer = ({
|
||||
|
||||
{isDefined(thread) && (
|
||||
<>
|
||||
<FrontComponentHostCommunicationApiEffect thread={thread} />
|
||||
<FrontComponentUpdateHostCommunicationApiEffect
|
||||
thread={thread}
|
||||
frontComponentHostCommunicationApi={
|
||||
frontComponentHostCommunicationApi
|
||||
}
|
||||
/>
|
||||
<FrontComponentInitializeHostCommunicationApiEffect thread={thread} />
|
||||
<FrontComponentUpdateContextEffect
|
||||
thread={thread}
|
||||
executionContext={executionContext}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
export { FrontComponentRenderer } from './host/components/FrontComponentRenderer';
|
||||
export { componentRegistry } from './host/generated/host-component-registry';
|
||||
export { FrontComponentErrorEffect } from './remote/components/FrontComponentErrorEffect';
|
||||
export { FrontComponentHostCommunicationApiEffect } from './remote/components/FrontComponentHostCommunicationApiEffect';
|
||||
export { FrontComponentInitializeHostCommunicationApiEffect } from './remote/components/FrontComponentInitializeHostCommunicationApiEffect';
|
||||
export { FrontComponentUpdateContextEffect } from './remote/components/FrontComponentUpdateContextEffect';
|
||||
export { FrontComponentUpdateHostCommunicationApiEffect } from './remote/components/FrontComponentUpdateHostCommunicationApiEffect';
|
||||
export { FrontComponentWorkerEffect } from './remote/components/FrontComponentWorkerEffect';
|
||||
export {
|
||||
HtmlA,
|
||||
|
||||
+3
-3
@@ -3,13 +3,13 @@ import { type WorkerExports } from '@/types/WorkerExports';
|
||||
import { type ThreadWebWorker } from '@quilted/threads';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
type FrontComponentHostCommunicationApiEffectProps = {
|
||||
type FrontComponentInitializeHostCommunicationApiEffectProps = {
|
||||
thread: ThreadWebWorker<WorkerExports, FrontComponentHostCommunicationApi>;
|
||||
};
|
||||
|
||||
export const FrontComponentHostCommunicationApiEffect = ({
|
||||
export const FrontComponentInitializeHostCommunicationApiEffect = ({
|
||||
thread,
|
||||
}: FrontComponentHostCommunicationApiEffectProps) => {
|
||||
}: FrontComponentInitializeHostCommunicationApiEffectProps) => {
|
||||
useEffect(() => {
|
||||
thread.imports.initializeHostCommunicationApi().catch((error) => {
|
||||
console.error('Failed to initialize host communication API:', error);
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { type FrontComponentHostCommunicationApi } from '@/types/FrontComponentHostCommunicationApi';
|
||||
import { type WorkerExports } from '@/types/WorkerExports';
|
||||
import { type ThreadWebWorker } from '@quilted/threads';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
type FrontComponentUpdateHostCommunicationApiEffectProps = {
|
||||
thread: ThreadWebWorker<WorkerExports, FrontComponentHostCommunicationApi>;
|
||||
frontComponentHostCommunicationApi: FrontComponentHostCommunicationApi;
|
||||
};
|
||||
|
||||
export const FrontComponentUpdateHostCommunicationApiEffect = ({
|
||||
thread,
|
||||
frontComponentHostCommunicationApi,
|
||||
}: FrontComponentUpdateHostCommunicationApiEffectProps) => {
|
||||
useEffect(() => {
|
||||
Object.assign(thread.exports, frontComponentHostCommunicationApi);
|
||||
}, [thread, frontComponentHostCommunicationApi]);
|
||||
|
||||
return null;
|
||||
};
|
||||
+16
-5
@@ -1,8 +1,8 @@
|
||||
import { ThreadWebWorker, release, retain } from '@quilted/threads';
|
||||
import { RemoteReceiver } from '@remote-dom/core/receivers';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { type ConfirmationModalCaller } from 'twenty-shared/types';
|
||||
import { type CommandConfirmationModalResult } from 'twenty-sdk';
|
||||
import { type ConfirmationModalCaller } from 'twenty-shared/types';
|
||||
import { type FrontComponentHostCommunicationApi } from '../../types/FrontComponentHostCommunicationApi';
|
||||
import { type SdkClientUrls } from '../../types/HostToWorkerRenderContext';
|
||||
import { type WorkerExports } from '../../types/WorkerExports';
|
||||
@@ -17,13 +17,26 @@ type CommandMenuItemConfirmationModalResultBrowserEventDetail = {
|
||||
confirmationResult: CommandConfirmationModalResult;
|
||||
};
|
||||
|
||||
const noopAsync = async () => {};
|
||||
|
||||
const HOST_COMMUNICATION_API_NOOP_INITIALIZATION: FrontComponentHostCommunicationApi =
|
||||
{
|
||||
navigate: noopAsync,
|
||||
requestAccessTokenRefresh: async () => '',
|
||||
openSidePanelPage: noopAsync,
|
||||
openCommandConfirmationModal: noopAsync,
|
||||
unmountFrontComponent: noopAsync,
|
||||
enqueueSnackbar: noopAsync,
|
||||
closeSidePanel: noopAsync,
|
||||
updateProgress: noopAsync,
|
||||
};
|
||||
|
||||
type FrontComponentWorkerEffectProps = {
|
||||
componentUrl: string;
|
||||
applicationAccessToken?: string;
|
||||
apiUrl?: string;
|
||||
sdkClientUrls?: SdkClientUrls;
|
||||
frontComponentId: string;
|
||||
frontComponentHostCommunicationApi: FrontComponentHostCommunicationApi;
|
||||
setReceiver: React.Dispatch<React.SetStateAction<RemoteReceiver | null>>;
|
||||
setThread: React.Dispatch<
|
||||
React.SetStateAction<ThreadWebWorker<
|
||||
@@ -40,7 +53,6 @@ export const FrontComponentWorkerEffect = ({
|
||||
apiUrl,
|
||||
sdkClientUrls,
|
||||
frontComponentId,
|
||||
frontComponentHostCommunicationApi,
|
||||
setReceiver,
|
||||
setThread,
|
||||
setError,
|
||||
@@ -68,7 +80,7 @@ export const FrontComponentWorkerEffect = ({
|
||||
WorkerExports,
|
||||
FrontComponentHostCommunicationApi
|
||||
>(worker, {
|
||||
exports: frontComponentHostCommunicationApi,
|
||||
exports: { ...HOST_COMMUNICATION_API_NOOP_INITIALIZATION },
|
||||
});
|
||||
|
||||
const handleCommandMenuItemConfirmationModalResultBrowserEvent = (
|
||||
@@ -135,7 +147,6 @@ export const FrontComponentWorkerEffect = ({
|
||||
setError,
|
||||
setReceiver,
|
||||
setThread,
|
||||
frontComponentHostCommunicationApi,
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user