diff options
author | Grégoire Aubert <gregoire.aubert@sonarsource.com> | 2024-10-16 11:52:23 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-10-22 20:03:09 +0000 |
commit | 54166222f6a6f6e6feaf482b81f89bf732045ff3 (patch) | |
tree | 275e0fc6c0cdbbc66fdf7b4fb64435d74e5705a6 /server/sonar-web/src/main/js | |
parent | fb204bcee8178d160c88323f6ba8e471935bd982 (diff) | |
download | sonarqube-54166222f6a6f6e6feaf482b81f89bf732045ff3.tar.gz sonarqube-54166222f6a6f6e6feaf482b81f89bf732045ff3.zip |
SONAR-23205 Add lazy loading on most routes to improve build and dev server perfs
Diffstat (limited to 'server/sonar-web/src/main/js')
36 files changed, 313 insertions, 52 deletions
diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx index 605c7910ce1..d2031afbc0b 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.tsx +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.tsx @@ -33,10 +33,10 @@ import { createBrowserRouter, createRoutesFromElements, } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; import accountRoutes from '../../apps/account/routes'; import auditLogsRoutes from '../../apps/audit-logs/routes'; import backgroundTasksRoutes from '../../apps/background-tasks/routes'; -import ChangeAdminPasswordApp from '../../apps/change-admin-password/ChangeAdminPasswordApp'; import codeRoutes from '../../apps/code/routes'; import codingRulesRoutes from '../../apps/coding-rules/routes'; import componentMeasuresRoutes from '../../apps/component-measures/routes'; @@ -50,11 +50,11 @@ import permissionTemplatesRoutes from '../../apps/permission-templates/routes'; import { globalPermissionsRoutes, projectPermissionsRoutes } from '../../apps/permissions/routes'; import projectActivityRoutes from '../../apps/projectActivity/routes'; import projectBranchesRoutes from '../../apps/projectBranches/routes'; -import ProjectDeletionApp from '../../apps/projectDeletion/App'; +import projectDeletionRoutes from '../../apps/projectDeletion/routes'; import projectDumpRoutes from '../../apps/projectDump/routes'; import projectInfoRoutes from '../../apps/projectInformation/routes'; -import ProjectKeyApp from '../../apps/projectKey/ProjectKeyApp'; -import ProjectLinksApp from '../../apps/projectLinks/ProjectLinksApp'; +import projectKeyRoutes from '../../apps/projectKey/routes'; +import projectLinksRoutes from '../../apps/projectLinks/routes'; import projectNewCodeDefinitionRoutes from '../../apps/projectNewCode/routes'; import projectQualityGateRoutes from '../../apps/projectQualityGate/routes'; import projectQualityProfilesRoutes from '../../apps/projectQualityProfiles/routes'; @@ -62,7 +62,7 @@ import projectsRoutes from '../../apps/projects/routes'; import projectsManagementRoutes from '../../apps/projectsManagement/routes'; import qualityGatesRoutes from '../../apps/quality-gates/routes'; import qualityProfilesRoutes from '../../apps/quality-profiles/routes'; -import SecurityHotspotsApp from '../../apps/security-hotspots/SecurityHotspotsApp'; +import securityHotspotsRoutes from '../../apps/security-hotspots/routes'; import sessionsRoutes from '../../apps/sessions/routes'; import settingsRoutes from '../../apps/settings/routes'; import systemRoutes from '../../apps/system/routes'; @@ -81,17 +81,13 @@ import AdminContainer from '../components/AdminContainer'; import App from '../components/App'; import ComponentContainer from '../components/ComponentContainer'; import DocumentationRedirect from '../components/DocumentationRedirect'; -import FormattingHelp from '../components/FormattingHelp'; import GlobalContainer from '../components/GlobalContainer'; import Landing from '../components/Landing'; import MigrationContainer from '../components/MigrationContainer'; import NonAdminPagesContainer from '../components/NonAdminPagesContainer'; import NotFound from '../components/NotFound'; -import PluginRiskConsent from '../components/PluginRiskConsent'; import ProjectAdminContainer from '../components/ProjectAdminContainer'; -import ResetPassword from '../components/ResetPassword'; import SimpleContainer from '../components/SimpleContainer'; -import SonarLintConnection from '../components/SonarLintConnection'; import { DEFAULT_APP_STATE } from '../components/app-state/AppStateContext'; import AppStateContextProvider from '../components/app-state/AppStateContextProvider'; import { @@ -123,8 +119,12 @@ function renderComponentRoutes() { element={<ProjectPageExtension />} /> {projectIssuesRoutes()} +<<<<<<< HEAD {dependenciesRoutes()} <Route path="security_hotspots" element={<SecurityHotspotsApp />} /> +======= + {securityHotspotsRoutes()} +>>>>>>> 6803c465323 (SONAR-23205 Add lazy loading on most routes to improve build and dev server perfs) {projectQualityGateRoutes()} {projectQualityProfilesRoutes()} {projectInfoRoutes()} @@ -144,9 +144,9 @@ function renderComponentRoutes() { {settingsRoutes()} {webhooksRoutes()} - <Route path="deletion" element={<ProjectDeletionApp />} /> - <Route path="links" element={<ProjectLinksApp />} /> - <Route path="key" element={<ProjectKeyApp />} /> + {projectDeletionRoutes()} + {projectLinksRoutes()} + {projectKeyRoutes()} </Route> {projectPermissionsRoutes()} </Route> @@ -185,6 +185,14 @@ function renderRedirects() { ); } +const FormattingHelp = lazyLoadComponent(() => import('../components/FormattingHelp')); +const SonarLintConnection = lazyLoadComponent(() => import('../components/SonarLintConnection')); +const ResetPassword = lazyLoadComponent(() => import('../components/ResetPassword')); +const ChangeAdminPasswordApp = lazyLoadComponent( + () => import('../../apps/change-admin-password/ChangeAdminPasswordApp'), +); +const PluginRiskConsent = lazyLoadComponent(() => import('../components/PluginRiskConsent')); + const router = createBrowserRouter( createRoutesFromElements( <> diff --git a/server/sonar-web/src/main/js/apps/audit-logs/routes.tsx b/server/sonar-web/src/main/js/apps/audit-logs/routes.tsx index 0eb7f96e57d..7178d9ff58d 100644 --- a/server/sonar-web/src/main/js/apps/audit-logs/routes.tsx +++ b/server/sonar-web/src/main/js/apps/audit-logs/routes.tsx @@ -19,8 +19,10 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import AuditApp from './components/AuditApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; const routes = () => <Route path="audit" element={<AuditApp />} />; +const AuditApp = lazyLoadComponent(() => import('./components/AuditApp')); + export default routes; diff --git a/server/sonar-web/src/main/js/apps/background-tasks/routes.tsx b/server/sonar-web/src/main/js/apps/background-tasks/routes.tsx index d31a23bf1fc..f50eb2fb0f9 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/routes.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import BackgroundTasksApp from './components/BackgroundTasksApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const BackgroundTasksApp = lazyLoadComponent(() => import('./components/BackgroundTasksApp')); const routes = () => <Route path="background_tasks" element={<BackgroundTasksApp />} />; diff --git a/server/sonar-web/src/main/js/apps/code/routes.tsx b/server/sonar-web/src/main/js/apps/code/routes.tsx index 7710f63cdd3..11c029616c3 100644 --- a/server/sonar-web/src/main/js/apps/code/routes.tsx +++ b/server/sonar-web/src/main/js/apps/code/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import CodeApp from './components/CodeApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const CodeApp = lazyLoadComponent(() => import('./components/CodeApp')); const routes = () => <Route path="code" element={<CodeApp />} />; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx b/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx index 8ac74338daa..67a18a55a23 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/routes.tsx @@ -19,10 +19,12 @@ */ import React, { useEffect } from 'react'; import { Route, useLocation, useNavigate } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; import { RawQuery } from '~sonar-aligned/types/router'; -import CodingRulesApp from './components/CodingRulesApp'; import { parseQuery, serializeQuery } from './query'; +const CodingRulesApp = lazyLoadComponent(() => import('./components/CodingRulesApp')); + const EXPECTED_SPLIT_PARTS = 2; function parseHash(hash: string): RawQuery { diff --git a/server/sonar-web/src/main/js/apps/component-measures/routes.tsx b/server/sonar-web/src/main/js/apps/component-measures/routes.tsx index a547a34802e..debc43d2744 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/routes.tsx +++ b/server/sonar-web/src/main/js/apps/component-measures/routes.tsx @@ -19,10 +19,12 @@ */ import React from 'react'; import { Navigate, Route, useParams, useSearchParams } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; import { searchParamsToQuery } from '~sonar-aligned/helpers/router'; import NavigateWithParams from '../../app/utils/NavigateWithParams'; import { omitNil } from '../../helpers/request'; -import ComponentMeasuresApp from './components/ComponentMeasuresApp'; + +const ComponentMeasuresApp = lazyLoadComponent(() => import('./components/ComponentMeasuresApp')); const routes = () => ( <Route path="component_measures"> diff --git a/server/sonar-web/src/main/js/apps/dependencies/routes.tsx b/server/sonar-web/src/main/js/apps/dependencies/routes.tsx index 27525c61107..0c9ab45fb5c 100644 --- a/server/sonar-web/src/main/js/apps/dependencies/routes.tsx +++ b/server/sonar-web/src/main/js/apps/dependencies/routes.tsx @@ -20,7 +20,9 @@ import React from 'react'; import { Route } from 'react-router-dom'; -import DependenciesApp from './DependenciesApp'; +import { lazyLoadComponent } from '../../sonar-aligned/helpers/lazyLoadComponent'; + +const DependenciesApp = lazyLoadComponent(() => import('./DependenciesApp')); export const dependenciesRoutes = () => <Route path="dependencies" element={<DependenciesApp />} />; diff --git a/server/sonar-web/src/main/js/apps/groups/routes.tsx b/server/sonar-web/src/main/js/apps/groups/routes.tsx index db9738ea9d3..7f46c245ae3 100644 --- a/server/sonar-web/src/main/js/apps/groups/routes.tsx +++ b/server/sonar-web/src/main/js/apps/groups/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import GroupsApp from './GroupsApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const GroupsApp = lazyLoadComponent(() => import('./GroupsApp')); const routes = () => <Route path="groups" element={<GroupsApp />} />; diff --git a/server/sonar-web/src/main/js/apps/issues/routes.tsx b/server/sonar-web/src/main/js/apps/issues/routes.tsx index 7f30e41a0db..48cbe65591f 100644 --- a/server/sonar-web/src/main/js/apps/issues/routes.tsx +++ b/server/sonar-web/src/main/js/apps/issues/routes.tsx @@ -19,9 +19,11 @@ */ import React, { useEffect } from 'react'; import { Route, useNavigate, useSearchParams } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; import { omitNil } from '../../helpers/request'; import { IssueType } from '../../types/issues'; -import IssuesApp from './components/IssuesApp'; + +const IssuesApp = lazyLoadComponent(() => import('./components/IssuesApp')); export const globalIssuesRoutes = () => <Route path="issues" element={<IssuesApp />} />; diff --git a/server/sonar-web/src/main/js/apps/marketplace/routes.tsx b/server/sonar-web/src/main/js/apps/marketplace/routes.tsx index 39fa3ef5239..8dedc452273 100644 --- a/server/sonar-web/src/main/js/apps/marketplace/routes.tsx +++ b/server/sonar-web/src/main/js/apps/marketplace/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import MarketplaceAppContainer from './MarketplaceAppContainer'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const MarketplaceAppContainer = lazyLoadComponent(() => import('./MarketplaceAppContainer')); export const routes = () => <Route path="marketplace" element={<MarketplaceAppContainer />} />; diff --git a/server/sonar-web/src/main/js/apps/overview/routes.tsx b/server/sonar-web/src/main/js/apps/overview/routes.tsx index a0434016ce6..1a2249ef833 100644 --- a/server/sonar-web/src/main/js/apps/overview/routes.tsx +++ b/server/sonar-web/src/main/js/apps/overview/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import App from './components/App'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const App = lazyLoadComponent(() => import('./components/App')); const routes = () => <Route path="dashboard" element={<App />} />; diff --git a/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx b/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx index 7bd12ec84eb..9dbdef25593 100644 --- a/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx +++ b/server/sonar-web/src/main/js/apps/permission-templates/routes.tsx @@ -19,7 +19,11 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import PermissionTemplatesApp from './components/PermissionTemplatesApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const PermissionTemplatesApp = lazyLoadComponent( + () => import('./components/PermissionTemplatesApp'), +); const routes = () => <Route path="permission_templates" element={<PermissionTemplatesApp />} />; diff --git a/server/sonar-web/src/main/js/apps/permissions/routes.tsx b/server/sonar-web/src/main/js/apps/permissions/routes.tsx index 0a46773795e..c2fa8129d22 100644 --- a/server/sonar-web/src/main/js/apps/permissions/routes.tsx +++ b/server/sonar-web/src/main/js/apps/permissions/routes.tsx @@ -19,8 +19,14 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import GlobalPermissionsApp from './global/components/PermissionsGlobalApp'; -import PermissionsProjectApp from './project/components/PermissionsProjectApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const GlobalPermissionsApp = lazyLoadComponent( + () => import('./global/components/PermissionsGlobalApp'), +); +const PermissionsProjectApp = lazyLoadComponent( + () => import('./project/components/PermissionsProjectApp'), +); export const globalPermissionsRoutes = () => ( <Route path="permissions" element={<GlobalPermissionsApp />} /> diff --git a/server/sonar-web/src/main/js/apps/projectActivity/routes.tsx b/server/sonar-web/src/main/js/apps/projectActivity/routes.tsx index 3bd17ae6488..31cbc16ae8c 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectActivity/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectActivityApp from './components/ProjectActivityApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectActivityApp = lazyLoadComponent(() => import('./components/ProjectActivityApp')); const routes = () => <Route path="project/activity" element={<ProjectActivityApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectBranches/routes.tsx b/server/sonar-web/src/main/js/apps/projectBranches/routes.tsx index 0e278472115..5efbbd4a633 100644 --- a/server/sonar-web/src/main/js/apps/projectBranches/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectBranches/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectBranchesApp from './ProjectBranchesApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectBranchesApp = lazyLoadComponent(() => import('./ProjectBranchesApp')); const routes = () => <Route path="branches" element={<ProjectBranchesApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectDeletion/routes.tsx b/server/sonar-web/src/main/js/apps/projectDeletion/routes.tsx new file mode 100644 index 00000000000..d6974af0f41 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectDeletion/routes.tsx @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import { Route } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const App = lazyLoadComponent(() => import('./App')); + +const routes = () => <Route path="deletion" element={<App />} />; + +export default routes; diff --git a/server/sonar-web/src/main/js/apps/projectDump/routes.tsx b/server/sonar-web/src/main/js/apps/projectDump/routes.tsx index 1cb748338c7..b757c6c7f93 100644 --- a/server/sonar-web/src/main/js/apps/projectDump/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectDump/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectDumpApp from './ProjectDumpApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectDumpApp = lazyLoadComponent(() => import('./ProjectDumpApp')); const routes = () => <Route path="import_export" element={<ProjectDumpApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectInformation/routes.tsx b/server/sonar-web/src/main/js/apps/projectInformation/routes.tsx index 903beaf840e..61f6295b5b1 100644 --- a/server/sonar-web/src/main/js/apps/projectInformation/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectInformation/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectInformationApp from './ProjectInformationApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectInformationApp = lazyLoadComponent(() => import('./ProjectInformationApp')); const routes = () => <Route path="project/information" element={<ProjectInformationApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectKey/routes.tsx b/server/sonar-web/src/main/js/apps/projectKey/routes.tsx new file mode 100644 index 00000000000..592c0751106 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectKey/routes.tsx @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import { Route } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectKeyApp = lazyLoadComponent(() => import('./ProjectKeyApp')); + +const routes = () => <Route path="key" element={<ProjectKeyApp />} />; + +export default routes; diff --git a/server/sonar-web/src/main/js/apps/projectLinks/routes.tsx b/server/sonar-web/src/main/js/apps/projectLinks/routes.tsx new file mode 100644 index 00000000000..d7718698ade --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectLinks/routes.tsx @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import { Route } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectLinksApp = lazyLoadComponent(() => import('./ProjectLinksApp')); + +const routes = () => <Route path="links" element={<ProjectLinksApp />} />; + +export default routes; diff --git a/server/sonar-web/src/main/js/apps/projectNewCode/routes.tsx b/server/sonar-web/src/main/js/apps/projectNewCode/routes.tsx index 9ab18067b63..75666bd89fc 100644 --- a/server/sonar-web/src/main/js/apps/projectNewCode/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectNewCode/routes.tsx @@ -19,7 +19,11 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectNewCodeDefinitionApp from './components/ProjectNewCodeDefinitionApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectNewCodeDefinitionApp = lazyLoadComponent( + () => import('./components/ProjectNewCodeDefinitionApp'), +); const routes = () => <Route path="baseline" element={<ProjectNewCodeDefinitionApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectQualityGate/routes.tsx b/server/sonar-web/src/main/js/apps/projectQualityGate/routes.tsx index 67db45e1f78..dbe8257b94f 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityGate/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityGate/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectQualityGateApp from './ProjectQualityGateApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectQualityGateApp = lazyLoadComponent(() => import('./ProjectQualityGateApp')); const routes = () => <Route path="project/quality_gate" element={<ProjectQualityGateApp />} />; diff --git a/server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.tsx b/server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.tsx index 11b8f414d2c..8acac8ae60b 100644 --- a/server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectQualityProfiles/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectQualityProfilesApp from './ProjectQualityProfilesApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectQualityProfilesApp = lazyLoadComponent(() => import('./ProjectQualityProfilesApp')); const routes = () => ( <Route path="project/quality_profiles" element={<ProjectQualityProfilesApp />} /> diff --git a/server/sonar-web/src/main/js/apps/projects/routes.tsx b/server/sonar-web/src/main/js/apps/projects/routes.tsx index 62a2cb6ceba..cf062a6bc9e 100644 --- a/server/sonar-web/src/main/js/apps/projects/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projects/routes.tsx @@ -19,12 +19,16 @@ */ import React from 'react'; import { Navigate, Route } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; import { save } from '../../helpers/storage'; -import CreateProjectPage from '../create/project/CreateProjectPage'; -import DefaultPageSelector from './components/DefaultPageSelector'; -import FavoriteProjectsContainer from './components/FavoriteProjectsContainer'; import { PROJECTS_ALL, PROJECTS_DEFAULT_FILTER } from './utils'; +const DefaultPageSelector = lazyLoadComponent(() => import('./components/DefaultPageSelector')); +const FavoriteProjectsContainer = lazyLoadComponent( + () => import('./components/FavoriteProjectsContainer'), +); +const CreateProjectPage = lazyLoadComponent(() => import('../create/project/CreateProjectPage')); + function PersistNavigate() { save(PROJECTS_DEFAULT_FILTER, PROJECTS_ALL); diff --git a/server/sonar-web/src/main/js/apps/projectsManagement/routes.tsx b/server/sonar-web/src/main/js/apps/projectsManagement/routes.tsx index 5e766881a53..0a3c7a85cea 100644 --- a/server/sonar-web/src/main/js/apps/projectsManagement/routes.tsx +++ b/server/sonar-web/src/main/js/apps/projectsManagement/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ProjectManagementApp from './ProjectManagementApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const ProjectManagementApp = lazyLoadComponent(() => import('./ProjectManagementApp')); const routes = () => <Route path="projects_management" element={<ProjectManagementApp />} />; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/routes.tsx b/server/sonar-web/src/main/js/apps/quality-gates/routes.tsx index c3cf1a8f8fd..4765280f5fb 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/routes.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import App from './components/App'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const App = lazyLoadComponent(() => import('./components/App')); const routes = () => ( <Route path="quality_gates"> diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/routes.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/routes.tsx index a6182ec8110..7909d2d3b96 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/routes.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/routes.tsx @@ -19,12 +19,14 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import ChangelogContainer from './changelog/ChangelogContainer'; -import ComparisonContainer from './compare/ComparisonContainer'; -import ProfileContainer from './components/ProfileContainer'; -import QualityProfilesApp from './components/QualityProfilesApp'; -import ProfileDetails from './details/ProfileDetails'; -import HomeContainer from './home/HomeContainer'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const QualityProfilesApp = lazyLoadComponent(() => import('./components/QualityProfilesApp')); +const HomeContainer = lazyLoadComponent(() => import('./home/HomeContainer')); +const ProfileContainer = lazyLoadComponent(() => import('./components/ProfileContainer')); +const ProfileDetails = lazyLoadComponent(() => import('./details/ProfileDetails')); +const ChangelogContainer = lazyLoadComponent(() => import('./changelog/ChangelogContainer')); +const ComparisonContainer = lazyLoadComponent(() => import('./compare/ComparisonContainer')); export enum QualityProfilePath { SHOW = 'show', diff --git a/server/sonar-web/src/main/js/apps/security-hotspots/routes.tsx b/server/sonar-web/src/main/js/apps/security-hotspots/routes.tsx new file mode 100644 index 00000000000..7d75b302b05 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/security-hotspots/routes.tsx @@ -0,0 +1,28 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import React from 'react'; +import { Route } from 'react-router-dom'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const SecurityHotspotsApp = lazyLoadComponent(() => import('./SecurityHotspotsApp')); + +const routes = () => <Route path="security_hotspots" element={<SecurityHotspotsApp />} />; + +export default routes; diff --git a/server/sonar-web/src/main/js/apps/settings/routes.tsx b/server/sonar-web/src/main/js/apps/settings/routes.tsx index 6e01fcb5b8d..a2ce4ea9874 100644 --- a/server/sonar-web/src/main/js/apps/settings/routes.tsx +++ b/server/sonar-web/src/main/js/apps/settings/routes.tsx @@ -19,8 +19,10 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import SettingsApp from './components/SettingsApp'; -import EncryptionApp from './encryption/EncryptionApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const SettingsApp = lazyLoadComponent(() => import('./components/SettingsApp')); +const EncryptionApp = lazyLoadComponent(() => import('./encryption/EncryptionApp')); const routes = () => ( <Route path="settings"> diff --git a/server/sonar-web/src/main/js/apps/system/routes.tsx b/server/sonar-web/src/main/js/apps/system/routes.tsx index 55351850983..cf8319590a6 100644 --- a/server/sonar-web/src/main/js/apps/system/routes.tsx +++ b/server/sonar-web/src/main/js/apps/system/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import SystemApp from './components/SystemApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const SystemApp = lazyLoadComponent(() => import('./components/SystemApp')); export const routes = () => <Route path="system" element={<SystemApp />} />; diff --git a/server/sonar-web/src/main/js/apps/tutorials/routes.tsx b/server/sonar-web/src/main/js/apps/tutorials/routes.tsx index 3556deb36d8..d08cadabfc4 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/routes.tsx +++ b/server/sonar-web/src/main/js/apps/tutorials/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import TutorialsApp from './components/TutorialsApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const TutorialsApp = lazyLoadComponent(() => import('./components/TutorialsApp')); const routes = () => <Route path="tutorials" element={<TutorialsApp />} />; diff --git a/server/sonar-web/src/main/js/apps/users/routes.tsx b/server/sonar-web/src/main/js/apps/users/routes.tsx index 337bec0bf33..3920d1ca079 100644 --- a/server/sonar-web/src/main/js/apps/users/routes.tsx +++ b/server/sonar-web/src/main/js/apps/users/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import UsersApp from './UsersApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const UsersApp = lazyLoadComponent(() => import('./UsersApp')); export const routes = () => <Route path="users" element={<UsersApp />} />; diff --git a/server/sonar-web/src/main/js/apps/web-api-v2/routes.tsx b/server/sonar-web/src/main/js/apps/web-api-v2/routes.tsx index 36df5337c4c..e85d40f8c42 100644 --- a/server/sonar-web/src/main/js/apps/web-api-v2/routes.tsx +++ b/server/sonar-web/src/main/js/apps/web-api-v2/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import WebApiApp from './WebApiApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const WebApiApp = lazyLoadComponent(() => import('./WebApiApp')); const routes = () => <Route path="web_api_v2" element={<WebApiApp />} />; diff --git a/server/sonar-web/src/main/js/apps/web-api/routes.tsx b/server/sonar-web/src/main/js/apps/web-api/routes.tsx index 3468f7ce9d9..6f2537898c0 100644 --- a/server/sonar-web/src/main/js/apps/web-api/routes.tsx +++ b/server/sonar-web/src/main/js/apps/web-api/routes.tsx @@ -19,7 +19,9 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import WebApiApp from './components/WebApiApp'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; + +const WebApiApp = lazyLoadComponent(() => import('./components/WebApiApp')); const routes = () => ( <Route path="web_api"> diff --git a/server/sonar-web/src/main/js/apps/webhooks/routes.tsx b/server/sonar-web/src/main/js/apps/webhooks/routes.tsx index 1aaab6eb14a..ce4b06474ad 100644 --- a/server/sonar-web/src/main/js/apps/webhooks/routes.tsx +++ b/server/sonar-web/src/main/js/apps/webhooks/routes.tsx @@ -19,8 +19,10 @@ */ import React from 'react'; import { Route } from 'react-router-dom'; -import App from './components/App'; +import { lazyLoadComponent } from '~sonar-aligned/helpers/lazyLoadComponent'; -export const routes = () => <Route path="webhooks" element={<App />} />; +const WebhooksApp = lazyLoadComponent(() => import('./components/App')); + +export const routes = () => <Route path="webhooks" element={<WebhooksApp />} />; export default routes; diff --git a/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx b/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx new file mode 100644 index 00000000000..0d47d9a8b89 --- /dev/null +++ b/server/sonar-web/src/main/js/sonar-aligned/helpers/lazyLoadComponent.tsx @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { FlagMessage } from 'design-system'; +import React, { Component, lazy, Suspense } from 'react'; +import { translate } from '../../helpers/l10n'; +import { requestTryAndRepeatUntil } from '../../helpers/request'; + +export function lazyLoadComponent<T extends React.ComponentType<any>>( + factory: () => Promise<{ default: T }>, + displayName?: string, +) { + const LazyComponent = lazy(() => + requestTryAndRepeatUntil(factory, { max: 2, slowThreshold: 2 }, () => true), + ); + + function LazyComponentWrapper(props: React.ComponentProps<T>) { + return ( + <LazyErrorBoundary> + <Suspense fallback={null}> + <LazyComponent {...props} /> + </Suspense> + </LazyErrorBoundary> + ); + } + + LazyComponentWrapper.displayName = displayName; + return LazyComponentWrapper; +} + +interface ErrorBoundaryProps { + children: React.ReactNode; +} + +interface ErrorBoundaryState { + hasError: boolean; +} + +export class LazyErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> { + state: ErrorBoundaryState = { hasError: false }; + + static getDerivedStateFromError() { + // Update state so the next render will show the fallback UI. + return { hasError: true }; + } + + render() { + if (this.state.hasError) { + return ( + <FlagMessage variant="error">{translate('default_component_error_message')}</FlagMessage> + ); + } + return this.props.children; + } +} |