Remove dead React 17 compatibility (#81080)
Remove dead React 17 compat
This commit is contained in:
14
bun.lock
14
bun.lock
@@ -161,7 +161,6 @@
|
||||
"typescript7": "npm:typescript@7.0.2",
|
||||
"underscore": "^1.13.8",
|
||||
"url": "^0.11.4",
|
||||
"use-sync-external-store": "^1.6.0",
|
||||
"yup": "^0.32.11",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -251,7 +250,6 @@
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/sinonjs__fake-timers": "^15.0.1",
|
||||
"@types/underscore": "^1.13.0",
|
||||
"@types/use-sync-external-store": "^1.5.0",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"ajv": "^8.5.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
@@ -1986,7 +1984,7 @@
|
||||
|
||||
"@types/unist": ["@types/unist@2.0.5", "", {}, "sha512-wnra4Vw9dopnuybR6HBywJ/URYpYrKLoepBTEtgfJup8Ahoi2zJECPP2cwiXp7btTvOT2CULv87aQRA4eZSP6g=="],
|
||||
|
||||
"@types/use-sync-external-store": ["@types/use-sync-external-store@1.5.0", "", {}, "sha512-5dyB8nLC/qogMrlCizZnYWQTA4lnb/v+It+sqNl5YnSRAPMlIqY/X0Xn+gZw8vOL+TgTTr28VEbn3uf8fUtAkw=="],
|
||||
"@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
|
||||
|
||||
"@types/uuid": ["@types/uuid@9.0.8", "", {}, "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA=="],
|
||||
|
||||
@@ -5382,7 +5380,7 @@
|
||||
|
||||
"use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" } }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="],
|
||||
|
||||
"use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||
"use-sync-external-store": ["use-sync-external-store@1.5.0", "", {}, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
||||
|
||||
"util": ["util@0.12.5", "", { "dependencies": { "inherits": "^2.0.3", "is-arguments": "^1.0.4", "is-generator-function": "^1.0.7", "is-typed-array": "^1.1.3", "which-typed-array": "^1.1.2" } }, "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA=="],
|
||||
|
||||
@@ -5866,10 +5864,6 @@
|
||||
|
||||
"@tiptap/extension-bubble-menu/@floating-ui/dom": ["@floating-ui/dom@1.6.12", "", { "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.8" } }, "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w=="],
|
||||
|
||||
"@tiptap/react/@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="],
|
||||
|
||||
"@tiptap/react/use-sync-external-store": ["use-sync-external-store@1.5.0", "", {}, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
||||
|
||||
"@tiptap/starter-kit/@tiptap/extension-blockquote": ["@tiptap/extension-blockquote@3.2.0", "", {}, "sha512-ivOvkzkpj/+1i6cZwUr1M+T/knci2XMl8NW/Q6g70Kx2TinEoFjOGnDi34j1mVznyzhxVlY9jm3Xvv4s2+Ni/w=="],
|
||||
|
||||
"@tiptap/starter-kit/@tiptap/extension-bold": ["@tiptap/extension-bold@3.2.0", "", {}, "sha512-YuwK/muBzc0r7VFV0CcnF5Otg90zfUW2D5x+KpSF0e9bUBltSvitHgRaKWFwbPAgXYwkh6+ftxEazbXeqyTv8Q=="],
|
||||
@@ -6642,6 +6636,8 @@
|
||||
|
||||
"miller-rabin/bn.js": ["bn.js@4.11.9", "", {}, "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw=="],
|
||||
|
||||
"mobx-react-lite/use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="],
|
||||
|
||||
"mocha/chokidar": ["chokidar@3.5.3", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw=="],
|
||||
|
||||
"mocha/glob": ["glob@8.1.0", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^5.0.1", "once": "^1.3.0" } }, "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ=="],
|
||||
@@ -7212,8 +7208,6 @@
|
||||
|
||||
"zrender/tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="],
|
||||
|
||||
"zustand/use-sync-external-store": ["use-sync-external-store@1.5.0", "", {}, "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A=="],
|
||||
|
||||
"@babel/generator/@jridgewell/trace-mapping/@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@babel/generator/@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.4.15", "", {}, "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="],
|
||||
|
||||
@@ -76,7 +76,6 @@ const RESOLVE_ALIASES = {
|
||||
process.env.MB_EDITION === "ee"
|
||||
? ENTERPRISE_SRC_PATH + "/sdk-plugins"
|
||||
: SRC_PATH + "/plugins/noop",
|
||||
"sdk-specific-imports": SRC_PATH + "/utils/noop",
|
||||
};
|
||||
|
||||
module.exports = { RESOLVE_ALIASES };
|
||||
|
||||
@@ -80,9 +80,7 @@
|
||||
"frontend/src/embedding-sdk-bundle/components/private/SdkBreadcrumbs/setup.spec.tsx": "self",
|
||||
"frontend/src/embedding-sdk-bundle/embedding-sdk-bootstrap.ts": "entry",
|
||||
"frontend/src/embedding-sdk-bundle/index.ts": "entry",
|
||||
"frontend/src/embedding-sdk-bundle/lib/polyfill/use-sync-external-store.ts": "global",
|
||||
"frontend/src/embedding-sdk-bundle/lib/sdk-public-path.ts": "global",
|
||||
"frontend/src/embedding-sdk-bundle/lib/sdk-specific-imports.ts": "entry",
|
||||
"frontend/src/embedding-sdk-bundle/store/index.ts": "self",
|
||||
"frontend/src/embedding-sdk-bundle/store/listener-middleware.ts": "self",
|
||||
"frontend/src/embedding-sdk-bundle/store/use-sdk-selector.ts": "self",
|
||||
@@ -201,7 +199,6 @@
|
||||
"frontend/src/metabase/utils/csp-setup.ts": "global",
|
||||
"frontend/src/metabase/utils/date-time.ts": "self",
|
||||
"frontend/src/metabase/utils/i18n.ts": "global",
|
||||
"frontend/src/metabase/utils/react-compat.unit.ts": "self",
|
||||
"frontend/src/metabase/utils/scripts-sandbox/distortions-blocked-apis.ts": "self",
|
||||
"frontend/src/metabase/utils/scripts-sandbox/distortions-dom-mutate.ts": "self",
|
||||
"frontend/src/metabase/utils/settings.ts": "self",
|
||||
|
||||
@@ -18,9 +18,6 @@ import { initializePlugins } from "sdk-ee-plugins";
|
||||
|
||||
initializePlugins();
|
||||
|
||||
// Imports which are only applicable to the embedding sdk, and not the new iframe embedding.
|
||||
import "sdk-specific-imports";
|
||||
|
||||
import { sdkBundleExports } from "./sdk-bundle-exports";
|
||||
|
||||
import { defineBuildInfo } from "metabase/embedding-sdk/lib/define-build-info";
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from "react";
|
||||
import { useSyncExternalStore } from "use-sync-external-store/shim";
|
||||
|
||||
// Monkey-patches useSyncExternalStore if we are in React 17,
|
||||
// where useSyncExternalStore is not available.
|
||||
// This is used in react-redux v8, until they've dropped the shim in v9.
|
||||
const shouldShimExternalStore = () => !("useSyncExternalStore" in React);
|
||||
|
||||
if (shouldShimExternalStore()) {
|
||||
React.useSyncExternalStore = useSyncExternalStore;
|
||||
}
|
||||
@@ -6,8 +6,7 @@
|
||||
*
|
||||
* Without this, an on-demand chunk would be requested relative to the host
|
||||
* page's base URL (where the SDK chunks don't exist) and fail with a
|
||||
* `ChunkLoadError`. This is why those dependencies used to be force-imported
|
||||
* eagerly in `./sdk-specific-imports`.
|
||||
* `ChunkLoadError`.
|
||||
*
|
||||
* Both the chunked bootstrap and the legacy monolithic bundle are served from
|
||||
* `app/embedding-sdk.js`, with their split/on-demand chunks living one level
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* The imports here are only called from the Embedding SDK.
|
||||
* This file is not imported from the main app, including the new iframe embedding.
|
||||
*
|
||||
* This is aliased as `sdk-specific-imports` in the SDK's webpack config.
|
||||
*/
|
||||
|
||||
// Polyfills useSyncExternalStore for React 17 for backwards compatibility.
|
||||
import "./polyfill/use-sync-external-store";
|
||||
|
||||
/**
|
||||
* NOTE: heavy dependencies that are lazily imported in the main codebase
|
||||
* (`jspdf`, `html2canvas-pro` for PDF / image export; `react-virtualized` via
|
||||
* the pivot table grid; `leaflet` via the map renderer) are intentionally NOT
|
||||
* eagerly imported here. They are loaded on demand via dynamic `import()`, so
|
||||
* they no longer weigh down the SDK's critical-path bundle. On-demand chunks
|
||||
* resolve against the runtime `publicPath` set in `./sdk-public-path`.
|
||||
*/
|
||||
@@ -4,13 +4,12 @@ import {
|
||||
flexRender,
|
||||
} from "@tanstack/react-table";
|
||||
import React, { useCallback } from "react";
|
||||
import type { Root } from "react-dom/client";
|
||||
import { type Root, createRoot } from "react-dom/client";
|
||||
|
||||
import type { ColumnOptions, DataGridTheme } from "metabase/data-grid/types";
|
||||
import { pickRowsToMeasure } from "metabase/data-grid/utils/column-sizing";
|
||||
import { MeasurementProviders } from "metabase/ui/components/theme/MeasurementProviders";
|
||||
import { createMeasurementContainer } from "metabase/utils/measure-container";
|
||||
import { renderRoot, unmountRoot } from "metabase/utils/react-compat";
|
||||
import { isNotNull } from "metabase/utils/types";
|
||||
|
||||
import { DataGridThemeProvider } from "./use-table-theme";
|
||||
@@ -90,7 +89,7 @@ export const useMeasureColumnWidths = <TData, TValue>(
|
||||
onMeasured(measuredColumnSizingMap);
|
||||
|
||||
setTimeout(() => {
|
||||
unmountRoot(measureRootTree, measureRoot);
|
||||
measureRootTree?.unmount();
|
||||
document.body.removeChild(measureRoot);
|
||||
}, 0);
|
||||
};
|
||||
@@ -167,7 +166,8 @@ export const useMeasureColumnWidths = <TData, TValue>(
|
||||
? measurementRenderWrapper(wrappedContent)
|
||||
: wrappedContent;
|
||||
|
||||
measureRootTree = renderRoot(content, measureRoot);
|
||||
measureRootTree = createRoot(measureRoot);
|
||||
measureRootTree.render(content);
|
||||
},
|
||||
[table, columnsOptions, theme, measurementRenderWrapper],
|
||||
);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { type Row, type Table, flexRender } from "@tanstack/react-table";
|
||||
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||
import type { Root } from "react-dom/client";
|
||||
import { type Root, createRoot } from "react-dom/client";
|
||||
|
||||
import { SortableHeaderPill } from "metabase/ui";
|
||||
import { MeasurementProviders } from "metabase/ui/components/theme/MeasurementProviders";
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
createMeasurementContainer,
|
||||
removeMeasurementContainer,
|
||||
} from "metabase/utils/measure-container";
|
||||
import { renderRoot } from "metabase/utils/react-compat";
|
||||
|
||||
import {
|
||||
CELL_HORIZONTAL_PADDING,
|
||||
@@ -383,7 +382,7 @@ export function useColumnSizing<TData extends TreeNodeData>({
|
||||
const [isMeasured, setIsMeasured] = useState(false);
|
||||
const measureRootRef = useRef<{
|
||||
element: HTMLDivElement;
|
||||
tree: Root | undefined;
|
||||
tree: Root;
|
||||
} | null>(null);
|
||||
|
||||
const allRows = table.getRowModel().flatRows;
|
||||
@@ -460,7 +459,8 @@ export function useColumnSizing<TData extends TreeNodeData>({
|
||||
</MeasurementProviders>
|
||||
);
|
||||
|
||||
const tree = renderRoot(content, measureElement);
|
||||
const tree = createRoot(measureElement);
|
||||
tree.render(content);
|
||||
measureRootRef.current = { element: measureElement, tree };
|
||||
}, [
|
||||
measurementColumnsKey,
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { Root } from "react-dom/client";
|
||||
|
||||
import { unmountRoot } from "metabase/utils/react-compat";
|
||||
|
||||
interface MeasurementContainerOptions {
|
||||
fontSize?: string;
|
||||
}
|
||||
@@ -31,10 +29,10 @@ export function createMeasurementContainer(
|
||||
|
||||
export function removeMeasurementContainer(
|
||||
container: HTMLDivElement,
|
||||
tree: Root | undefined,
|
||||
tree: Root,
|
||||
): void {
|
||||
setTimeout(() => {
|
||||
unmountRoot(tree, container);
|
||||
tree.unmount();
|
||||
document.body.removeChild(container);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// Support React 17 backwards compatibility for the Embedding SDK
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { type Root, createRoot } from "react-dom/client";
|
||||
|
||||
export function renderRoot(
|
||||
content: React.JSX.Element,
|
||||
element: Element,
|
||||
): Root | undefined {
|
||||
const reactVersion = getMajorReactVersion();
|
||||
|
||||
if (reactVersion <= 17) {
|
||||
// eslint-disable-next-line react/no-deprecated -- legacy usage
|
||||
ReactDOM.render(content, element);
|
||||
return;
|
||||
}
|
||||
|
||||
const root = createRoot(element);
|
||||
root.render(content);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
export function unmountRoot(root?: Root, element?: Element) {
|
||||
const reactVersion = getMajorReactVersion();
|
||||
|
||||
if (reactVersion <= 17 && element) {
|
||||
// eslint-disable-next-line react/no-deprecated -- legacy usage
|
||||
ReactDOM.unmountComponentAtNode(element);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root) {
|
||||
root.unmount();
|
||||
}
|
||||
}
|
||||
|
||||
export const getMajorReactVersion = () => {
|
||||
const versionParts = React.version.split(".").map(Number);
|
||||
|
||||
return versionParts[0];
|
||||
};
|
||||
@@ -1,41 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
import { getMajorReactVersion } from "./react-compat";
|
||||
|
||||
describe("getMajorReactVersion", () => {
|
||||
const versions = [
|
||||
{ version: "0.14.0", expected: 0 },
|
||||
{ version: "15.0.0", expected: 15 },
|
||||
{ version: "16.0.0", expected: 16 },
|
||||
{ version: "16.8.0", expected: 16 },
|
||||
{ version: "17.0.0", expected: 17 },
|
||||
{ version: "17.0.2", expected: 17 },
|
||||
{ version: "18.0.0", expected: 18 },
|
||||
{ version: "18.1.0", expected: 18 },
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetModules();
|
||||
});
|
||||
|
||||
it.each(versions)(
|
||||
"should return $expected for React version $version",
|
||||
({ version, expected }) => {
|
||||
Object.defineProperty(React, "version", {
|
||||
value: version,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
expect(getMajorReactVersion()).toBe(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it("should return NaN for an invalid version string", () => {
|
||||
Object.defineProperty(React, "version", {
|
||||
value: "invalid-version",
|
||||
writable: true,
|
||||
});
|
||||
|
||||
expect(getMajorReactVersion()).toBeNaN();
|
||||
});
|
||||
});
|
||||
@@ -69,11 +69,6 @@ const baseConfig = {
|
||||
"<rootDir>/frontend/src/metabase/utils/noop.ts",
|
||||
"ee-plugins": "<rootDir>/frontend/src/metabase/utils/noop.ts",
|
||||
"ee-overrides": "<rootDir>/frontend/src/metabase/utils/noop.ts",
|
||||
/**
|
||||
* Imports which are only applicable to the embedding sdk.
|
||||
* As we use SDK components in new iframe embedding, we need to import them here.
|
||||
**/
|
||||
"sdk-specific-imports": "<rootDir>/frontend/src/metabase/utils/noop.ts",
|
||||
/**
|
||||
* Docs snippets are loaded as raw text (asset/source) in rspack.
|
||||
* In Jest, mock them as plain strings.
|
||||
|
||||
@@ -170,7 +170,6 @@
|
||||
"typescript7": "npm:typescript@7.0.2",
|
||||
"underscore": "^1.13.8",
|
||||
"url": "^0.11.4",
|
||||
"use-sync-external-store": "^1.6.0",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -260,7 +259,6 @@
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/sinonjs__fake-timers": "^15.0.1",
|
||||
"@types/underscore": "^1.13.0",
|
||||
"@types/use-sync-external-store": "^1.5.0",
|
||||
"@vitejs/plugin-react": "^6.0.2",
|
||||
"ajv": "^8.5.0",
|
||||
"babel-loader": "^9.1.2",
|
||||
|
||||
@@ -432,9 +432,6 @@ config.resolve.alias = {
|
||||
"sdk-iframe-embedding-ee-plugins":
|
||||
ENTERPRISE_SRC_PATH + "/sdk-iframe-embedding-plugins",
|
||||
"ee-overrides": ENTERPRISE_SRC_PATH + "/overrides",
|
||||
|
||||
// Allows importing side effects that applies only to the SDK.
|
||||
"sdk-specific-imports": SDK_BUNDLE_SRC_PATH + "/lib/sdk-specific-imports.ts",
|
||||
};
|
||||
|
||||
if (config.cache) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
"zrender/lib/core/types": ["./node_modules/zrender/lib/core/types"],
|
||||
"ee-plugins": ["./frontend/src/metabase/plugins/noop"],
|
||||
"sdk-ee-plugins": ["./frontend/src/metabase/plugins/noop"],
|
||||
"sdk-specific-imports": ["./frontend/src/metabase/utils/noop"],
|
||||
"sdk-iframe-embedding-ee-plugins": [
|
||||
"./frontend/src/metabase/plugins/noop"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user