From 0f34702b3566953d9c966321d0a8a191a67b433e Mon Sep 17 00:00:00 2001 From: ElementRobot Date: Wed, 21 Dec 2022 10:04:11 +0000 Subject: [PATCH] [Backport staging] Load RTE component only when needed (#9807) Use react lazy to load rte component (cherry picked from commit d6e447b9344c650fc1ac1eabf232681a2c4f9a63) Co-authored-by: Florian Duros --- .../DynamicImportWysiwygComposer.tsx | 36 +++++++++++++++ .../wysiwyg_composer/EditWysiwygComposer.tsx | 45 ++++++++++--------- .../wysiwyg_composer/SendWysiwygComposer.tsx | 3 +- .../views/rooms/wysiwyg_composer/index.ts | 6 ++- .../EditWysiwygComposer-test.tsx | 24 +++++++++- .../SendWysiwygComposer-test.tsx | 6 +-- 6 files changed, 92 insertions(+), 28 deletions(-) create mode 100644 src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx diff --git a/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx new file mode 100644 index 0000000000..65a365b06d --- /dev/null +++ b/src/components/views/rooms/wysiwyg_composer/DynamicImportWysiwygComposer.tsx @@ -0,0 +1,36 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { ComponentProps, lazy, Suspense } from "react"; + +const SendComposer = lazy(() => import("./SendWysiwygComposer")); +const EditComposer = lazy(() => import("./EditWysiwygComposer")); + +export function DynamicImportSendWysiwygComposer(props: ComponentProps) { + return ( + }> + + + ); +} + +export function DynamicImportEditWysiwygComposer(props: ComponentProps) { + return ( + }> + + + ); +} diff --git a/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx index 275d30bb1f..36264b7763 100644 --- a/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/EditWysiwygComposer.tsx @@ -43,32 +43,35 @@ interface EditWysiwygComposerProps { className?: string; } -export function EditWysiwygComposer({ editorStateTransfer, className, ...props }: EditWysiwygComposerProps) { +// Default needed for React.lazy +export default function EditWysiwygComposer({ editorStateTransfer, className, ...props }: EditWysiwygComposerProps) { const initialContent = useInitialContent(editorStateTransfer); const isReady = !editorStateTransfer || initialContent !== undefined; const { editMessage, endEditing, onChange, isSaveDisabled } = useEditing(editorStateTransfer, initialContent); + if (!isReady) { + return null; + } + return ( - isReady && ( - - {(ref) => ( - <> - - - - )} - - ) + + {(ref) => ( + <> + + + + )} + ); } diff --git a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx index 4d72672167..78b24bb507 100644 --- a/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx +++ b/src/components/views/rooms/wysiwyg_composer/SendWysiwygComposer.tsx @@ -49,7 +49,8 @@ interface SendWysiwygComposerProps { menuPosition: AboveLeftOf; } -export function SendWysiwygComposer({ +// Default needed for React.lazy +export default function SendWysiwygComposer({ isRichTextEnabled, e2eStatus, menuPosition, diff --git a/src/components/views/rooms/wysiwyg_composer/index.ts b/src/components/views/rooms/wysiwyg_composer/index.ts index 55a3e79a19..c82f59ca89 100644 --- a/src/components/views/rooms/wysiwyg_composer/index.ts +++ b/src/components/views/rooms/wysiwyg_composer/index.ts @@ -14,6 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -export { SendWysiwygComposer } from "./SendWysiwygComposer"; -export { EditWysiwygComposer } from "./EditWysiwygComposer"; +export { + DynamicImportSendWysiwygComposer as SendWysiwygComposer, + DynamicImportEditWysiwygComposer as EditWysiwygComposer, +} from "./DynamicImportWysiwygComposer"; export { sendMessage } from "./utils/message"; diff --git a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx index cc53c88dc0..c0849145bf 100644 --- a/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/EditWysiwygComposer-test.tsx @@ -64,13 +64,35 @@ describe("EditWysiwygComposer", () => { ); }; + it("Should not render the component when not ready", async () => { + // When + const { rerender } = customRender(false); + await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"), { + timeout: 2000, + }); + + rerender( + + + + + , + ); + + // Then + await waitFor(() => expect(screen.queryByRole("textbox")).toBeNull()); + }); + describe("Initialize with content", () => { it("Should initialize useWysiwyg with html content", async () => { // When customRender(false, editorStateTransfer); - await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true")); // Then + await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"), { + timeout: 2000, + }); + await waitFor(() => expect(screen.getByRole("textbox")).toContainHTML(mockEvent.getContent()["formatted_body"]), ); diff --git a/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx index 669c611f8c..cdaf76d499 100644 --- a/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/SendWysiwygComposer-test.tsx @@ -24,7 +24,7 @@ import defaultDispatcher from "../../../../../src/dispatcher/dispatcher"; import { Action } from "../../../../../src/dispatcher/actions"; import { IRoomState } from "../../../../../src/components/structures/RoomView"; import { createTestClient, flushPromises, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils"; -import { SendWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer"; +import { SendWysiwygComposer } from "../../../../../src/components/views/rooms/wysiwyg_composer/"; import { aboveLeftOf } from "../../../../../src/components/structures/ContextMenu"; import { ComposerInsertPayload, ComposerType } from "../../../../../src/dispatcher/payloads/ComposerInsertPayload"; import { setSelection } from "../../../../../src/components/views/rooms/wysiwyg_composer/utils/selection"; @@ -101,12 +101,12 @@ describe("SendWysiwygComposer", () => { ); }; - it("Should render WysiwygComposer when isRichTextEnabled is at true", () => { + it("Should render WysiwygComposer when isRichTextEnabled is at true", async () => { // When customRender(jest.fn(), jest.fn(), false, true); // Then - expect(screen.getByTestId("WysiwygComposer")).toBeTruthy(); + await waitFor(() => expect(screen.getByTestId("WysiwygComposer")).toBeTruthy()); }); it("Should render PlainTextComposer when isRichTextEnabled is at false", () => {