From 077582e79595cfab90710515b6468fee3fde5933 Mon Sep 17 00:00:00 2001 From: yuri-sakharov <10849682+yuri-sakharov@users.noreply.github.com> Date: Sat, 6 Dec 2025 17:19:35 +0200 Subject: [PATCH] Added lazy load, visualizer and optimized bundle chunks (#635) * Added lazy load. * Added visualizer and improved hljs import only yaml * Optimized manualChunks --- frontend/eslint.config.js | 9 + frontend/package-lock.json | 254 ++++++++++++++++-- frontend/package.json | 1 + frontend/src/App.tsx | 5 +- .../modal/InstallChartModal/ChartValues.tsx | 5 +- .../modal/InstallChartModal/DefinedValues.tsx | 4 +- .../InstallReleaseChartModal.tsx | 53 ++-- .../InstallRepoChartModal.tsx | 39 ++- .../modal/InstallChartModal/ManifestDiff.tsx | 9 +- .../components/revision/RevisionDetails.tsx | 8 +- .../src/components/revision/RevisionDiff.tsx | 7 +- .../components/revision/RevisionResource.tsx | 5 +- frontend/src/pages/Revision.tsx | 21 +- frontend/vite.config.ts | 9 +- frontend/yarn.lock | 92 ++++++- 15 files changed, 437 insertions(+), 84 deletions(-) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index ed3ce6e..682db8d 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -139,6 +139,15 @@ export default defineConfig([ "tsc/config": ["error", { configFile: "./tsconfig.json" }], }, }, + { + files: ["vite.config.ts"], + languageOptions: { + parserOptions: { + project: "./tsconfig.node.json", // point to the tiny tsconfig + }, + }, + }, + { languageOptions: { globals: { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fa9123f..abcadca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -58,6 +58,7 @@ "lint-staged": "^16.2.7", "prettier": "^3.7.1", "prettier-plugin-tailwindcss": "^0.7.1", + "rollup-plugin-visualizer": "^6.0.5", "storybook": "10.0.8", "tailwindcss": "^4.1.17", "typescript": "^5.9.3", @@ -1582,31 +1583,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", - "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/pluginutils": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", @@ -4654,6 +4630,39 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5091,6 +5100,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -6867,6 +6886,31 @@ "@tailwindcss/postcss": "^4.1.17" } }, + "node_modules/flowbite-datepicker/node_modules/@rollup/plugin-node-resolve": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", + "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/flowbite-react": { "version": "0.12.10", "resolved": "https://registry.npmjs.org/flowbite-react/-/flowbite-react-0.12.10.tgz", @@ -7208,6 +7252,16 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", @@ -8043,6 +8097,22 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -8383,6 +8453,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -9919,6 +10002,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openapi-path-templating": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/openapi-path-templating/-/openapi-path-templating-2.2.1.tgz", @@ -11033,6 +11134,16 @@ "throttleit": "^1.0.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/requireindex": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", @@ -11166,6 +11277,60 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-visualizer": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.5.tgz", + "integrity": "sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "open": "^8.0.0", + "picomatch": "^4.0.2", + "source-map": "^0.7.4", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "rolldown": "1.x || ^1.0.0-beta", + "rollup": "2.x || 3.x || 4.x" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/rollup-plugin-visualizer/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -13144,6 +13309,16 @@ "repeat-string": "^1.5.2" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -13164,6 +13339,35 @@ "node": ">= 14.6" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 09fedfa..6a9a42b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,6 +54,7 @@ "lint-staged": "^16.2.7", "prettier": "^3.7.1", "prettier-plugin-tailwindcss": "^0.7.1", + "rollup-plugin-visualizer": "^6.0.5", "storybook": "10.0.8", "tailwindcss": "^4.1.17", "typescript": "^5.9.3", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index d60b455..36abeea 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,13 +5,14 @@ import RepositoryPage from "./pages/Repository"; import Revision from "./pages/Revision"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import type { FC } from "react"; -import { useState } from "react"; +import { useState, lazy } from "react"; import type { ErrorAlert } from "./context/ErrorModalContext"; import { ErrorModalContext } from "./context/ErrorModalContext"; import GlobalErrorModal from "./components/modal/GlobalErrorModal"; import { AppContextProvider } from "./context/AppContext"; import apiService from "./API/apiService"; -import DocsPage from "./pages/DocsPage"; + +const DocsPage = lazy(() => import("./pages/DocsPage")); const queryClient = new QueryClient({ defaultOptions: { diff --git a/frontend/src/components/modal/InstallChartModal/ChartValues.tsx b/frontend/src/components/modal/InstallChartModal/ChartValues.tsx index 6b729d7..602fdc8 100644 --- a/frontend/src/components/modal/InstallChartModal/ChartValues.tsx +++ b/frontend/src/components/modal/InstallChartModal/ChartValues.tsx @@ -1,5 +1,8 @@ -import hljs from "highlight.js"; +import hljs from "highlight.js/lib/core"; import Spinner from "../../Spinner"; +import yaml from "highlight.js/lib/languages/yaml"; + +hljs.registerLanguage("yaml", yaml); export const ChartValues = ({ chartValues, diff --git a/frontend/src/components/modal/InstallChartModal/DefinedValues.tsx b/frontend/src/components/modal/InstallChartModal/DefinedValues.tsx index eb1a3c4..9323953 100644 --- a/frontend/src/components/modal/InstallChartModal/DefinedValues.tsx +++ b/frontend/src/components/modal/InstallChartModal/DefinedValues.tsx @@ -8,7 +8,7 @@ interface DefinedValuesProps { loading: boolean; } -export const DefinedValues = ({ +const DefinedValues = ({ initialValue, chartValues, onUserValuesChange, @@ -24,3 +24,5 @@ export const DefinedValues = ({ ); }; + +export default DefinedValues; diff --git a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx index e402576..94568e1 100644 --- a/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx +++ b/frontend/src/components/modal/InstallChartModal/InstallReleaseChartModal.tsx @@ -1,5 +1,12 @@ import { useParams } from "react-router"; -import { useEffect, useEffectEvent, useMemo, useState } from "react"; +import { + useEffect, + useEffectEvent, + useMemo, + useState, + lazy, + Suspense, +} from "react"; import type { VersionData } from "../../../API/releases"; import { useChartReleaseValues, @@ -9,7 +16,6 @@ import { } from "../../../API/releases"; import Modal, { ModalButtonStyle } from "../Modal"; import { GeneralDetails } from "./GeneralDetails"; -import { ManifestDiff } from "./ManifestDiff"; import { useMutation } from "@tanstack/react-query"; import useNavigateWithSearchParams from "../../../hooks/useNavigateWithSearchParams"; import { VersionToInstall } from "./VersionToInstall"; @@ -18,10 +24,13 @@ import useCustomSearchParams from "../../../hooks/useCustomSearchParams"; import { useChartRepoValues } from "../../../API/repositories"; import { useDiffData } from "../../../API/shared"; import type { InstallChartModalProps } from "../../../data/types"; -import { DefinedValues } from "./DefinedValues"; import apiService from "../../../API/apiService"; import { InstallUpgradeTitle } from "./InstallUpgradeTitle"; import type { LatestChartVersion } from "../../../API/interfaces"; +import Spinner from "../../Spinner"; + +const DefinedValues = lazy(() => import("./DefinedValues")); +const ManifestDiff = lazy(() => import("./ManifestDiff")); export const InstallReleaseChartModal = ({ isOpen, @@ -222,24 +231,28 @@ export const InstallReleaseChartModal = ({ onNamespaceInput={setNamespace} /> - setUserValues(values)} - chartValues={chartValues} - loading={loadingReleaseValues} - /> + }> + setUserValues(values)} + chartValues={chartValues} + loading={loadingReleaseValues} + /> + - + }> + + ); }; diff --git a/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx b/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx index 8087811..50e67d5 100644 --- a/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx +++ b/frontend/src/components/modal/InstallChartModal/InstallRepoChartModal.tsx @@ -1,9 +1,15 @@ import { useParams } from "react-router"; -import { useEffect, useEffectEvent, useMemo, useState } from "react"; +import { + lazy, + Suspense, + useEffect, + useEffectEvent, + useMemo, + useState, +} from "react"; import { useGetVersions, useVersionData } from "../../../API/releases"; import Modal, { ModalButtonStyle } from "../Modal"; import { GeneralDetails } from "./GeneralDetails"; -import { ManifestDiff } from "./ManifestDiff"; import { useMutation } from "@tanstack/react-query"; import { useChartRepoValues } from "../../../API/repositories"; import useNavigateWithSearchParams from "../../../hooks/useNavigateWithSearchParams"; @@ -11,10 +17,13 @@ import { VersionToInstall } from "./VersionToInstall"; import { isNoneEmptyArray } from "../../../utils"; import { useDiffData } from "../../../API/shared"; import type { InstallChartModalProps } from "../../../data/types"; -import { DefinedValues } from "./DefinedValues"; import apiService from "../../../API/apiService"; import { InstallUpgradeTitle } from "./InstallUpgradeTitle"; import type { LatestChartVersion } from "../../../API/interfaces"; +import Spinner from "../../Spinner"; + +const DefinedValues = lazy(() => import("./DefinedValues")); +const ManifestDiff = lazy(() => import("./ManifestDiff")); export const InstallRepoChartModal = ({ isOpen, @@ -107,7 +116,7 @@ export const InstallRepoChartModal = ({ } = useDiffData({ selectedRepo: selectedRepo || "", versionsError: versionsError as unknown as string, // TODO fix it - currentVerManifest: "", // current version manifest should always be empty since its a fresh install + currentVerManifest: "", // current version manifest should always be empty since it's a fresh install selectedVerData, chart: chartAddress, }); @@ -208,16 +217,18 @@ export const InstallRepoChartModal = ({ loading={loadingChartValues} /> - + }> + + ); }; diff --git a/frontend/src/components/modal/InstallChartModal/ManifestDiff.tsx b/frontend/src/components/modal/InstallChartModal/ManifestDiff.tsx index 440ff6f..04269ad 100644 --- a/frontend/src/components/modal/InstallChartModal/ManifestDiff.tsx +++ b/frontend/src/components/modal/InstallChartModal/ManifestDiff.tsx @@ -1,17 +1,20 @@ import { Diff2HtmlUI } from "diff2html/lib/ui/js/diff2html-ui-base"; -import hljs from "highlight.js"; +import hljs from "highlight.js/lib/core"; +import yaml from "highlight.js/lib/languages/yaml"; import { useEffect, useRef } from "react"; import Spinner from "../../Spinner"; import { diffConfiguration } from "../../../utils"; +hljs.registerLanguage("yaml", yaml); + interface ManifestDiffProps { diff?: string; isLoading: boolean; error: string; } -export const ManifestDiff = ({ diff, isLoading, error }: ManifestDiffProps) => { +const ManifestDiff = ({ diff, isLoading, error }: ManifestDiffProps) => { const diffContainerRef = useRef(null); useEffect(() => { @@ -63,3 +66,5 @@ export const ManifestDiff = ({ diff, isLoading, error }: ManifestDiffProps) => { ); }; + +export default ManifestDiff; diff --git a/frontend/src/components/revision/RevisionDetails.tsx b/frontend/src/components/revision/RevisionDetails.tsx index 99d43dd..b36d43f 100644 --- a/frontend/src/components/revision/RevisionDetails.tsx +++ b/frontend/src/components/revision/RevisionDetails.tsx @@ -45,12 +45,12 @@ type RevisionDetailsProps = { latestRevision: number; }; -export default function RevisionDetails({ +const RevisionDetails = ({ release, installedRevision, isLatest, latestRevision, -}: RevisionDetailsProps) { +}: RevisionDetailsProps) => { const [searchParams] = useSearchParams(); const revisionTabs = [ @@ -307,7 +307,7 @@ export default function RevisionDetails({ ); -} +}; function RevisionTag({ caption, text }: RevisionTagProps) { return ( @@ -534,3 +534,5 @@ const Uninstall = () => { ); }; + +export default RevisionDetails; diff --git a/frontend/src/components/revision/RevisionDiff.tsx b/frontend/src/components/revision/RevisionDiff.tsx index 2712438..7d935b0 100644 --- a/frontend/src/components/revision/RevisionDiff.tsx +++ b/frontend/src/components/revision/RevisionDiff.tsx @@ -4,13 +4,14 @@ import { Diff2HtmlUI } from "diff2html/lib/ui/js/diff2html-ui-slim.js"; import { useGetReleaseInfoByType } from "../../API/releases"; import { useParams } from "react-router"; import useCustomSearchParams from "../../hooks/useCustomSearchParams"; - import parse from "html-react-parser"; - -import hljs from "highlight.js"; +import hljs from "highlight.js/lib/core"; +import yaml from "highlight.js/lib/languages/yaml"; import Spinner from "../Spinner"; import { diffConfiguration } from "../../utils"; +hljs.registerLanguage("yaml", yaml); + type RevisionDiffProps = { includeUserDefineOnly?: boolean; latestRevision: number; diff --git a/frontend/src/components/revision/RevisionResource.tsx b/frontend/src/components/revision/RevisionResource.tsx index 0b79d17..4620a9a 100644 --- a/frontend/src/components/revision/RevisionResource.tsx +++ b/frontend/src/components/revision/RevisionResource.tsx @@ -1,6 +1,7 @@ import { useMemo, useState } from "react"; import { useParams } from "react-router"; -import hljs from "highlight.js"; +import hljs from "highlight.js/lib/core"; +import yaml from "highlight.js/lib/languages/yaml"; import { RiExternalLinkLine } from "react-icons/ri"; import type { StructuredResources } from "../../API/releases"; @@ -15,6 +16,8 @@ import Badge, { getBadgeType } from "../Badge"; import Spinner from "../Spinner"; import { Troubleshoot } from "../Troubleshoot"; +hljs.registerLanguage("yaml", yaml); + interface Props { isLatest: boolean; } diff --git a/frontend/src/pages/Revision.tsx b/frontend/src/pages/Revision.tsx index 9a4f86d..2c2d383 100644 --- a/frontend/src/pages/Revision.tsx +++ b/frontend/src/pages/Revision.tsx @@ -1,12 +1,15 @@ -import { useMemo } from "react"; +import { useMemo, Suspense, lazy } from "react"; import { useParams } from "react-router"; -import RevisionDetails from "../components/revision/RevisionDetails"; import RevisionsList from "../components/revision/RevisionsList"; import type { ReleaseRevision } from "../data/types"; import { useQuery } from "@tanstack/react-query"; import apiService from "../API/apiService"; import Spinner from "../components/Spinner"; +const RevisionDetails = lazy( + () => import("../components/revision/RevisionDetails") +); + const descendingSort = (r1: ReleaseRevision, r2: ReleaseRevision) => r1.revision - r2.revision < 0 ? 1 : -1; @@ -62,12 +65,14 @@ function Revision() { ) : selectedRelease ? ( - + }> + + ) : null} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 679cc82..2fc8b8d 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -3,6 +3,7 @@ import { defineConfig, loadEnv } from "vite"; import react from "@vitejs/plugin-react"; import { viteStaticCopy } from "vite-plugin-static-copy"; import flowbiteReact from "flowbite-react/plugin/vite"; +import { visualizer } from "rollup-plugin-visualizer"; export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ""); @@ -12,6 +13,11 @@ export default defineConfig(({ mode }) => { react({ babel: { plugins: ["babel-plugin-react-compiler"] } }), // React and "babel-plugin-react-compiler" plugins should be first tailwindcss(), flowbiteReact(), + visualizer({ + filename: "../pkg/frontend/dist/stats.html", + gzipSize: true, + brotliSize: true, + }), viteStaticCopy({ targets: [ { @@ -36,8 +42,7 @@ export default defineConfig(({ mode }) => { rollupOptions: { output: { manualChunks: { - react: ["react", "react-dom", "react-router"], - vendors: ["luxon", "highlight.js", "diff2html", "swagger-ui-react"], + react: ["react", "react-dom", "react-router", "flowbite-react"], }, }, }, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 809258a..6db9f9d 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2568,6 +2568,15 @@ cli-truncate@^5.0.0: slice-ansi "^7.1.0" string-width "^8.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" @@ -2851,6 +2860,11 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" @@ -3215,7 +3229,7 @@ es-to-primitive@^1.3.0: "@esbuild/win32-ia32" "0.25.11" "@esbuild/win32-x64" "0.25.11" -escalade@^3.2.0: +escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== @@ -3762,6 +3776,11 @@ gensync@^1.0.0-beta.2: resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.0, get-east-asian-width@^1.3.1: version "1.4.0" resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz" @@ -4248,6 +4267,11 @@ is-decimal@^2.0.0: resolved "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz" integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" @@ -4417,6 +4441,13 @@ is-weakset@^2.0.3: call-bound "^1.0.3" get-intrinsic "^1.2.6" +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" @@ -5074,6 +5105,15 @@ onetime@^7.0.0: dependencies: mimic-function "^5.0.0" +open@^8.0.0: + version "8.4.2" + resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + openapi-path-templating@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/openapi-path-templating/-/openapi-path-templating-2.2.1.tgz" @@ -5233,6 +5273,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.3" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + picomatch@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz" @@ -5629,6 +5674,11 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + requireindex@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz" @@ -5698,6 +5748,16 @@ rfdc@^1.3.0, rfdc@^1.4.1: resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz" integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== +rollup-plugin-visualizer@^6.0.5: + version "6.0.5" + resolved "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.5.tgz" + integrity sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg== + dependencies: + open "^8.0.0" + picomatch "^4.0.2" + source-map "^0.7.4" + yargs "^17.5.1" + rollup@^4.43.0: version "4.52.5" resolved "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz" @@ -5966,6 +6026,11 @@ source-map@^0.5.7: resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== +source-map@^0.7.4: + version "0.7.6" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + source-map@~0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" @@ -6035,7 +6100,7 @@ string-argv@^0.3.2: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0, string-width@^4.2.0: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6836,6 +6901,11 @@ xml@=1.0.1: resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz" integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" @@ -6851,6 +6921,24 @@ yaml@^2.8.1: resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz" integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.5.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz"