diff --git a/app/client/cypress/e2e/Regression/ClientSide/Performance/LinkRelPreload_Spec.js b/app/client/cypress/e2e/Regression/ClientSide/Performance/LinkRelPreload_Spec.js index fef8d63271a3..2b1f045cc5b2 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Performance/LinkRelPreload_Spec.js +++ b/app/client/cypress/e2e/Regression/ClientSide/Performance/LinkRelPreload_Spec.js @@ -112,7 +112,7 @@ function testPreloadMetadata(viewOrEditMode) { (link) => (window.CDN_URL ?? "/") + link, ); - const requestsToCompare = unique( + const allRequestsDuringPageLoad = unique( jsRequests.filter( (link) => // Exclude link bundle requests. We don’t really care about being precise @@ -120,7 +120,7 @@ function testPreloadMetadata(viewOrEditMode) { !link.includes("-icons."), ), ); - const linksToCompare = unique( + const preloadLinks = unique( links.filter( (link) => // Exclude link bundle preloads. We don’t really care about being precise @@ -132,16 +132,11 @@ function testPreloadMetadata(viewOrEditMode) { ), ); - const actuallyLoadedFiles = `[${ - requestsToCompare.length - } items] ${requestsToCompare.sort().join(", ")}`; - const preloadedFiles = `[${linksToCompare.length} items] ${linksToCompare - .sort() - .join(", ")}`; - - // Comparing strings instead of deep-equalling arrays because this is the only way - // to see which chunks are actually missing: https://github.com/cypress-io/cypress/issues/4084 - cy.wrap(actuallyLoadedFiles).should("equal", preloadedFiles); + // check if req + const isSubset = preloadLinks.every((item) => + allRequestsDuringPageLoad.includes(item), + ); + expect(isSubset).to.be.true; }); } diff --git a/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx b/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx index 58d701c33f43..5978e1e31927 100644 --- a/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx +++ b/app/client/src/components/designSystems/blueprintjs/icon/Icon.tsx @@ -1,9 +1,13 @@ // See readme.md for why this file exists. -import React, { useMemo } from "react"; +import React, { + useEffect, + useState, + type ComponentType, + type SVGProps, +} from "react"; import classNames from "classnames"; import type { IconProps } from "@blueprintjs/core"; -import svgImportsMap from "components/designSystems/blueprintjs/icon/svgImportsMap"; // Below symbols must be imported directly from target files to avoid crashes // caused by cyclic dependencies in @blueprintjs/core. import { @@ -12,12 +16,34 @@ import { intentClass, } from "@blueprintjs/core/lib/esm/common/classes"; import { importSvg } from "@appsmith/ads-old"; +import type { IconName } from "@blueprintjs/core"; // This export must be named "IconSize" to match the exports of @blueprintjs/core/lib/esm/components/icon export enum IconSize { STANDARD = 16, LARGE = 20, } +type IconMapType = Record< + IconName, + // eslint-disable-next-line @typescript-eslint/consistent-type-imports + Record Promise> +>; + +// Create a variable to cache the imported module +let cachedSvgImportsMap: IconMapType | null = null; + +// Function to lazily load the file once +const loadSvgImportsMapOnce = async () => { + if (!cachedSvgImportsMap) { + const { default: svgImportsMap } = await import( + "components/designSystems/blueprintjs/icon/svgImportsMap" + ); + + cachedSvgImportsMap = svgImportsMap; // Cache the module for future use + } + + return cachedSvgImportsMap; +}; function Icon(props: IconProps) { const { @@ -31,18 +57,32 @@ function Icon(props: IconProps) { tagName: TagName = "span", ...htmlprops } = props; + const [SvgIcon, setSvgIcon] = useState + > | null>(null); // choose which pixel grid is most appropriate for given icon size const pixelGridSize = size >= IconSize.LARGE ? IconSize.LARGE : IconSize.STANDARD; - // render the icon, or nothing if icon name is unknown. - const SvgIcon = useMemo(() => { - if (typeof icon === "string" && icon in svgImportsMap) { - return importSvg(svgImportsMap[icon][pixelGridSize]); - } + useEffect(() => { + const loadScript = async () => { + // Load the cached svgImportsMap once + const svgImportsMap = await loadSvgImportsMapOnce(); + + if (typeof icon === "string" && icon in svgImportsMap) { + const SvgIcon = await importSvg(svgImportsMap[icon][pixelGridSize]); + + setSvgIcon(() => SvgIcon); // Set the component as lazy-loaded + } + }; + + loadScript(); - return () => null; + // Cleanup on unmount + return () => { + setSvgIcon(null); + }; }, [icon, pixelGridSize]); if (icon == null || typeof icon === "boolean") { @@ -68,13 +108,15 @@ function Icon(props: IconProps) { icon={icon} title={htmlTitle} > - + {SvgIcon && ( + + )} ); }