) => {
@@ -287,42 +289,61 @@ export const CompSelectionWrapper = React.memo((props: {
}
setHover(false);
},
- [setHover]
+ [nameDivRef.current, setHover]
);
- const selectableDivProps = props.isSelectable
- ? {
- onMouseOver,
- onMouseOut,
- onClick: props.onClick,
- $hover: hover || undefined,
- $showDashLine: editorState.showGridLines() || props.hidden,
- $isSelected: props.isSelected,
- $isHidden: props.hidden,
- }
- : {
- $hover: undefined,
- $showDashLine: false,
- $isSelected: false,
- $isHidden: false,
- };
+ const selectableDivProps = useMemo(() => {
+ return props.isSelectable
+ ? {
+ onMouseOver,
+ onMouseOut,
+ onClick: props.onClick,
+ $hover: hover || undefined,
+ $showDashLine: editorState.showGridLines() || props.hidden,
+ $isSelected: props.isSelected,
+ $isHidden: props.hidden,
+ }
+ : {
+ $hover: undefined,
+ $showDashLine: false,
+ $isSelected: false,
+ $isHidden: false,
+ };
+ }, [
+ hover,
+ props.hidden,
+ props.isSelected,
+ props.isSelectable,
+ ]);
+
+ const zIndex = useMemo(() => {
+ return props.isSelected
+ ? Layers.compSelected
+ : hover
+ ? Layers.compHover
+ : props.hidden
+ ? Layers.compHidden
+ : undefined;
+ }, [
+ hover,
+ props.hidden,
+ props.isSelected
+ ]);
- const zIndex = props.isSelected
- ? Layers.compSelected
- : hover
- ? Layers.compHover
- : props.hidden
- ? Layers.compHidden
- : undefined;
+ const needResizeDetector = useMemo(() => {
+ return props.autoHeight && !props.placeholder;
+ }, [props.autoHeight, props.placeholder]);
- const needResizeDetector = props.autoHeight && !props.placeholder;
const { ref: wrapperRef } = useResizeDetector({
onResize: props.onWrapperResize,
handleHeight: needResizeDetector,
handleWidth: false,
+ refreshMode: 'debounce',
+ refreshRate: 100,
});
// log.debug("CompSelectionWrapper. name: ", props.name, " zIndex: ", zIndex);
const { nameConfig, resizeIconSize } = props;
+
return (
@@ -380,4 +411,4 @@ export const CompSelectionWrapper = React.memo((props: {
);
-});
+}, (prev, next) => isEqual(prev, next));
diff --git a/client/packages/lowcoder/src/layout/gridItem.tsx b/client/packages/lowcoder/src/layout/gridItem.tsx
index 963c1c056..3594f3acd 100644
--- a/client/packages/lowcoder/src/layout/gridItem.tsx
+++ b/client/packages/lowcoder/src/layout/gridItem.tsx
@@ -113,8 +113,8 @@ export const GridItem = React.memo((props: GridItemProps) => {
maxRows: props.maxRows,
}, props.x, props.y, props.w, props.h)},
[
- props.margin,
- props.containerPadding,
+ JSON.stringify(props.margin),
+ JSON.stringify(props.containerPadding),
props.containerWidth,
props.cols,
props.rowHeight,
@@ -123,7 +123,6 @@ export const GridItem = React.memo((props: GridItemProps) => {
props.y,
props.w,
props.h,
- calcGridItemPosition,
]
);
@@ -230,8 +229,8 @@ export const GridItem = React.memo((props: GridItemProps) => {
y: yy,
});
}, [
- resizing,
- dragging,
+ JSON.stringify(resizing),
+ JSON.stringify(dragging),
props.cols,
props.maxRows,
props.x,
@@ -417,7 +416,7 @@ export const GridItem = React.memo((props: GridItemProps) => {
itemHeightRef.current = height;
}
adjustWrapperHeight(width, height);
- }, [itemHeightRef, adjustWrapperHeight]);
+ }, [itemHeightRef.current, adjustWrapperHeight]);
/**
* re-calculate the occupied gird-cells.
@@ -427,7 +426,7 @@ export const GridItem = React.memo((props: GridItemProps) => {
*/
const onWrapperSizeChange = useCallback(() => {
adjustWrapperHeight(undefined, itemHeightRef.current);
- }, [itemHeightRef, adjustWrapperHeight]);
+ }, [itemHeightRef.current, adjustWrapperHeight]);
const mixinChildWrapper = useCallback((child: React.ReactElement): React.ReactElement => {
const {
@@ -535,6 +534,21 @@ export const GridItem = React.memo((props: GridItemProps) => {
const pos = useMemo(calcPosition, [calcPosition]);
+ const transform = useMemo(() => {
+ return setTransform(
+ pos,
+ props.name,
+ props.autoHeight,
+ props.hidden,
+ Boolean(draggingUtils.isDragging())
+ )
+ }, [
+ JSON.stringify(pos),
+ props.name,
+ props.autoHeight,
+ props.hidden
+ ]);
+
const render = useMemo(() => {
let child = React.Children.only(children);
// Create the child element. We clone the existing element but modify its className and style.
@@ -563,13 +577,7 @@ export const GridItem = React.memo((props: GridItemProps) => {
cssTransforms: true,
}),
style: {
- ...setTransform(
- pos,
- props.name,
- props.autoHeight,
- props.hidden,
- Boolean(draggingUtils.isDragging())
- ),
+ ...transform,
opacity: layoutHide ? 0 : undefined,
pointerEvents: layoutHide ? "none" : "auto",
},
@@ -580,11 +588,12 @@ export const GridItem = React.memo((props: GridItemProps) => {
newChild = mixinDraggable(newChild, isDraggable);
return newChild;
}, [
- pos,
+ JSON.stringify(transform),
+ JSON.stringify(pos),
children,
elementRef,
- resizing,
- dragging,
+ Boolean(resizing),
+ Boolean(dragging),
isDraggable,
layoutHide,
zIndex,
@@ -593,8 +602,6 @@ export const GridItem = React.memo((props: GridItemProps) => {
props.className,
props.style,
props.static,
- props.autoHeight,
- props.hidden,
setTransform,
mixinChildWrapper,
mixinResizable,
diff --git a/client/packages/lowcoder/src/layout/gridLayout.tsx b/client/packages/lowcoder/src/layout/gridLayout.tsx
index 0b88786c2..0b25763b7 100644
--- a/client/packages/lowcoder/src/layout/gridLayout.tsx
+++ b/client/packages/lowcoder/src/layout/gridLayout.tsx
@@ -1,8 +1,8 @@
import clsx from "clsx";
import { colord } from "colord";
-import { UICompType } from "comps/uiCompRegistry";
+import type { UICompType } from "comps/uiCompRegistry";
import { ModulePrimaryColor, PrimaryColor } from "constants/style";
-import _ from "lodash";
+import _, { isEqual } from "lodash";
import log from "loglevel";
import React, { DragEvent, DragEventHandler, MouseEventHandler, ReactElement } from "react";
import ReactResizeDetector from "react-resize-detector";
@@ -21,7 +21,7 @@ import {
import { draggingUtils } from "./draggingUtils";
import { FlyOverInfo, FlyStartInfo } from "./flyInfo";
import { GridItem } from "./gridItem";
-import { GridLayoutProps } from "./gridLayoutPropTypes";
+import type { GridLayoutProps } from "./gridLayoutPropTypes";
import { GridLines } from "./gridLines";
import { changeItemOp, deleteItemOp, LayoutOp, renameItemOp } from "./layoutOp";
import { getUILayout, LayoutOps, layoutOpUtils } from "./layoutOpUtils";
@@ -1102,7 +1102,7 @@ const LayoutContainer = styled.div<{
}`}
`;
-export const ReactGridLayout = React.memo(GridLayout);
+export const ReactGridLayout = React.memo(GridLayout, (prev, next) => isEqual(prev, next));
function moveOrResize(
e: React.KeyboardEvent,
diff --git a/client/packages/lowcoder/src/layout/gridLines.tsx b/client/packages/lowcoder/src/layout/gridLines.tsx
index c7cfc1366..33b5eefec 100644
--- a/client/packages/lowcoder/src/layout/gridLines.tsx
+++ b/client/packages/lowcoder/src/layout/gridLines.tsx
@@ -1,6 +1,7 @@
import { CSSProperties } from "react";
import { calcGridColWidth, PositionParams } from "./calculateUtils";
import { Position, setTransform } from "./utils";
+import React from "react";
interface GridLineProps {
position: Position;
@@ -19,10 +20,10 @@ function setBackgroundProps(positionParams: PositionParams, lineColor: string):
};
}
-export function GridLines(props: GridLineProps) {
+export const GridLines = React.memo((props: GridLineProps) => {
const style = {
...setTransform(props.position),
...setBackgroundProps(props.positionParams, props.lineColor),
};
return ;
-}
+})
diff --git a/client/packages/lowcoder/vite.config.mts b/client/packages/lowcoder/vite.config.mts
index 9699e15db..1350607c1 100644
--- a/client/packages/lowcoder/vite.config.mts
+++ b/client/packages/lowcoder/vite.config.mts
@@ -1,5 +1,5 @@
import dotenv from "dotenv";
-import { defineConfig, ServerOptions, UserConfig } from "vite";
+import { defineConfig, PluginOption, ServerOptions, UserConfig } from "vite";
import react from "@vitejs/plugin-react";
import viteTsconfigPaths from "vite-tsconfig-paths";
import svgrPlugin from "vite-plugin-svgr";
@@ -12,6 +12,7 @@ import dynamicImport from 'vite-plugin-dynamic-import';
import { ensureLastSlash } from "./src/dev-utils/util";
import { buildVars } from "./src/dev-utils/buildVars";
import { globalDepPlugin } from "./src/dev-utils/globalDepPlguin";
+import { terser } from 'rollup-plugin-terser';
// import { nodePolyfills } from 'vite-plugin-node-polyfills'
dotenv.config();
@@ -66,6 +67,7 @@ export const viteConfig: UserConfig = {
},
base,
build: {
+ minify: "terser",
manifest: true,
target: "es2020",
cssTarget: "chrome87",
@@ -73,9 +75,117 @@ export const viteConfig: UserConfig = {
assetsDir: "static",
emptyOutDir: false,
rollupOptions: {
+ treeshake: {
+ moduleSideEffects: true,
+ propertyReadSideEffects: false,
+ tryCatchDeoptimization: false,
+ unknownGlobalSideEffects: false,
+ },
output: {
- chunkFileNames: "[hash].js",
+ inlineDynamicImports: false,
+ chunkFileNames: "[name]-[hash].js",
+ manualChunks: (id) => {
+ if (id.includes("node_modules")) {
+ // UI LIBRARIES
+ if (id.includes("@ant-design/icons")) return "ant-design-icons";
+ if (id.includes("node_modules/antd")) return "antd";
+ if (id.includes("styled-components")) return "styled-components";
+
+ // 🔹 BARCODE & QR CODE PROCESSING
+ if (id.includes("react-qr-barcode-scanner")) return "barcode";
+
+ // TEXT EDITORS & PARSERS
+ if (id.includes("codemirror")) return "codemirror";
+ if (id.includes("quill")) return "quill";
+ if (id.includes("react-json-view")) return "react-json-view";
+ if (id.includes("react-quill")) return "react-quill";
+ if (id.includes("remark-gfm")) return "remark-gfm";
+ if (id.includes("rehype-raw")) return "rehype-raw";
+ if (id.includes("rehype-sanitize")) return "rehype-sanitize";
+
+ // DRAG & DROP
+ if (id.includes("@dnd-kit")) return "dnd-kit";
+ if (id.includes("react-draggable")) return "react-draggable";
+ if (id.includes("react-grid-layout")) return "react-grid-layout";
+ if (id.includes("react-sortable-hoc")) return "react-sortable-hoc";
+
+ // ICONS & FONTS
+ if (id.includes("@fortawesome")) return "fontawesome";
+ if (id.includes("@remixicon")) return "remixicon";
+
+ // DATE/TIME HANDLING
+ if (id.includes("moment")) return "moment";
+ if (id.includes("date-fns")) return "date-fns";
+ if (id.includes("dayjs")) return "dayjs";
+
+ // UTILITIES & HELPERS
+ if (id.includes("clsx")) return "clsx";
+ if (id.includes("immer")) return "immer";
+ if (id.includes("lodash")) return "lodash";
+ if (id.includes("lodash-es")) return "lodash-es";
+ if (id.includes("uuid")) return "uuid";
+ if (id.includes("ua-parser-js")) return "ua-parser-js";
+ if (id.includes("html2canvas")) return "ua-parser-js";
+ if (id.includes("numbro")) return "numbro";
+
+ // FILE & DATA PROCESSING
+ if (id.includes("buffer")) return "buffer";
+ if (id.includes("file-saver")) return "file-saver";
+ if (id.includes("papaparse")) return "papaparse";
+ if (id.includes("parse5")) return "parse5";
+ if (id.includes("xlsx")) return "xlsx";
+ if (id.includes("alasql")) return "alasql";
+ if (id.includes("sql-formatter")) return "sql-formatter";
+
+ // NETWORK & HTTP
+ if (id.includes("axios")) return "axios";
+ if (id.includes("fetch")) return "fetch";
+ if (id.includes("http")) return "http-modules";
+ if (id.includes("https")) return "https-modules";
+
+ // WEB SOCKETS & STREAMING
+ if (id.includes("sockjs")) return "websockets";
+ if (id.includes("websocket")) return "websockets";
+
+ // STATE MANAGEMENT
+ if (id.includes("react-error-boundary")) return "react-error-boundary";
+ if (id.includes("redux-devtools-extension")) return "redux-devtools";
+
+ // POLYFILLS & BROWSER COMPATIBILITY
+ // if (id.includes("core-js")) return "core-js";
+ if (id.includes("regenerator-runtime")) return "regenerator-runtime";
+ if (id.includes("eslint4b-prebuilt-2")) return "eslint4b-prebuilt-2";
+
+ // MISCELLANEOUS
+ if (id.includes("cnchar")) return "cnchar";
+ if (id.includes("hotkeys-js")) return "hotkeys-js";
+ if (id.includes("loglevel")) return "loglevel";
+ if (id.includes("qrcode.react")) return "qrcode-react";
+ if (id.includes("react-joyride")) return "react-joyride";
+ if (id.includes("rc-trigger")) return "rc-trigger";
+ if (id.includes("really-relaxed-json")) return "really-relaxed-json";
+ if (id.includes("simplebar-react")) return "simplebar-react";
+ if (id.includes("react-documents")) return "react-documents";
+ if (id.includes("react-colorful")) return "react-colorful";
+ if (id.includes("react-best-gradient-color-picker")) return "react-best-gradient-color-picker";
+ if (id.includes("@supabase/supabase-js")) return "supabase";
+ return null;
+ }
+ return null;
+ },
},
+ plugins: [
+ terser({
+ compress: {
+ drop_console: true,
+ drop_debugger: true,
+ pure_funcs: ["console.info", "console.debug", "console.log"],
+ },
+ format: {
+ comments: /(@vite-ignore|webpackIgnore)/
+ },
+ }) as PluginOption,
+ ],
onwarn: (warning, warn) => {
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
return
@@ -84,6 +194,7 @@ export const viteConfig: UserConfig = {
},
},
commonjsOptions: {
+ transformMixedEsModules : true,
defaultIsModuleExports: (id) => {
if (id.indexOf("antd/lib") !== -1) {
return false;
@@ -178,7 +289,7 @@ const browserCheckConfig: UserConfig = {
copyPublicDir: true,
emptyOutDir: true,
lib: {
- formats: ["iife"],
+ formats: ["es"],
name: "BrowserCheck",
entry: "./src/browser-check.ts",
fileName: () => {
diff --git a/client/yarn.lock b/client/yarn.lock
index 1589f0bb7..1f364cbc2 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -14242,6 +14242,7 @@ coolshapes-react@lowcoder-org/coolshapes-react:
rehype-sanitize: ^5.0.1
remark-gfm: ^4.0.0
resize-observer-polyfill: ^1.5.1
+ rollup-plugin-terser: ^7.0.2
rollup-plugin-visualizer: ^5.9.2
simplebar-react: ^3.2.4
sql-formatter: ^8.2.0