From 7f0843df0c84a21510194413de1294148dc08628 Mon Sep 17 00:00:00 2001 From: David Paul Graham <43794491+dpgraham4401@users.noreply.github.com> Date: Tue, 3 Oct 2023 17:55:10 -0400 Subject: [PATCH] Code splitting (#598) * add rollupOptions to split third party dependencies into separate fils to decrease initial bundle size * migrate from react-router-dom's old route based system to the new 'data' router convert nested routes (site and manifest) to new browser router definition convert features to lazy loaded react components routed though rrd createBrowserRouter function * adjust feature directory exports so the feature components can be lazy loaded * implement private route and login page using the createBrowserRouter * move manifest features to separate directories and use dynamic import to implement code splitting * move static assets to new static directory --- client/public/static/robot-bad-sign.jpg | Bin 0 -> 21902 bytes client/public/static/robot-happy.jpg | Bin 0 -> 20634 bytes client/public/static/robot-wink.jpg | Bin 0 -> 19861 bytes .../{ => static}/under-construction.png | Bin client/src/App.tsx | 95 ++---------------- client/src/components/Ht/HtCard/HtCard.tsx | 4 +- .../{PrivateRoute => Layout}/PrivateRoute.tsx | 6 +- client/src/components/Layout/Root.tsx | 25 +++++ .../{Nav => Layout}/SideBarNavItem.tsx | 0 .../{Nav => Layout}/Sidebar.spec.tsx | 2 +- .../components/{Nav => Layout}/Sidebar.tsx | 0 .../{Nav => Layout}/TopNav.spec.tsx | 2 +- .../src/components/{Nav => Layout}/TopNav.tsx | 0 .../src/components/{Nav => Layout}/index.ts | 0 client/src/components/PrivateRoute/index.ts | 3 - client/src/env.d.ts | 5 + client/src/features/404/NotFound.tsx | 22 ++++ client/src/features/404/index.ts | 3 + .../SiteDetails/SiteDetails.tsx | 0 client/src/features/SiteDetails/index.ts | 3 + .../SiteList/SiteList.spec.tsx | 2 +- .../{haztrakSite => }/SiteList/SiteList.tsx | 0 client/src/features/SiteList/index.ts | 3 + .../features/comingSoon/UnderConstruction.tsx | 4 +- client/src/features/comingSoon/index.ts | 4 +- .../features/haztrakSite/SiteDetails/index.ts | 3 - .../features/haztrakSite/SiteList/index.ts | 3 - client/src/features/haztrakSite/Sites.tsx | 25 ----- client/src/features/haztrakSite/index.ts | 3 - client/src/features/help/index.ts | 4 +- client/src/features/home/Home.spec.tsx | 2 +- client/src/features/home/index.ts | 4 +- client/src/features/login/Login.tsx | 6 +- client/src/features/manifest/Manifest.tsx | 18 ---- client/src/features/manifest/index.ts | 3 - .../ManifestDetails.tsx | 0 client/src/features/manifestDetails/index.ts | 3 + .../ManifestList.tsx | 4 +- .../NewManifest.spec.tsx | 2 +- client/src/features/manifestList/index.ts | 3 + .../{manifest => newManifest}/NewManifest.tsx | 0 client/src/features/newManifest/index.ts | 3 + client/src/features/notifications/index.ts | 4 +- client/src/features/profile/index.ts | 4 +- client/src/index.tsx | 4 +- client/src/routes.tsx | 89 ++++++++++++++++ client/vite.config.ts | 22 +++- 47 files changed, 216 insertions(+), 176 deletions(-) create mode 100644 client/public/static/robot-bad-sign.jpg create mode 100644 client/public/static/robot-happy.jpg create mode 100644 client/public/static/robot-wink.jpg rename client/public/{ => static}/under-construction.png (100%) rename client/src/components/{PrivateRoute => Layout}/PrivateRoute.tsx (69%) create mode 100644 client/src/components/Layout/Root.tsx rename client/src/components/{Nav => Layout}/SideBarNavItem.tsx (100%) rename client/src/components/{Nav => Layout}/Sidebar.spec.tsx (94%) rename client/src/components/{Nav => Layout}/Sidebar.tsx (100%) rename client/src/components/{Nav => Layout}/TopNav.spec.tsx (94%) rename client/src/components/{Nav => Layout}/TopNav.tsx (100%) rename client/src/components/{Nav => Layout}/index.ts (100%) delete mode 100644 client/src/components/PrivateRoute/index.ts create mode 100644 client/src/features/404/NotFound.tsx create mode 100644 client/src/features/404/index.ts rename client/src/features/{haztrakSite => }/SiteDetails/SiteDetails.tsx (100%) create mode 100644 client/src/features/SiteDetails/index.ts rename client/src/features/{haztrakSite => }/SiteList/SiteList.spec.tsx (95%) rename client/src/features/{haztrakSite => }/SiteList/SiteList.tsx (100%) create mode 100644 client/src/features/SiteList/index.ts delete mode 100644 client/src/features/haztrakSite/SiteDetails/index.ts delete mode 100644 client/src/features/haztrakSite/SiteList/index.ts delete mode 100644 client/src/features/haztrakSite/Sites.tsx delete mode 100644 client/src/features/haztrakSite/index.ts delete mode 100644 client/src/features/manifest/Manifest.tsx delete mode 100644 client/src/features/manifest/index.ts rename client/src/features/{manifest => manifestDetails}/ManifestDetails.tsx (100%) create mode 100644 client/src/features/manifestDetails/index.ts rename client/src/features/{manifest => manifestList}/ManifestList.tsx (97%) rename client/src/features/{manifest => manifestList}/NewManifest.spec.tsx (96%) create mode 100644 client/src/features/manifestList/index.ts rename client/src/features/{manifest => newManifest}/NewManifest.tsx (100%) create mode 100644 client/src/features/newManifest/index.ts create mode 100644 client/src/routes.tsx diff --git a/client/public/static/robot-bad-sign.jpg b/client/public/static/robot-bad-sign.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0e9bd4243ac8c0c88b26982344056b57ed6d0097 GIT binary patch literal 21902 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 literal 0 HcmV?d00001 diff --git a/client/public/static/robot-wink.jpg b/client/public/static/robot-wink.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dcf189a59310d04697f5d19a650f29147a8831e6 GIT binary patch literal 19861 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 literal 0 HcmV?d00001 diff --git a/client/public/under-construction.png b/client/public/static/under-construction.png similarity index 100% rename from client/public/under-construction.png rename to client/public/static/under-construction.png diff --git a/client/src/App.tsx b/client/src/App.tsx index 8303346a9..330fb302e 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,29 +1,16 @@ import { ErrorBoundary } from 'components/ErrorBoundary'; -import { HtCard } from 'components/Ht'; -import { Sidebar, TopNav } from 'components/Nav'; -import { PrivateRoute } from 'components/PrivateRoute'; -import { UnderConstruction } from 'features/comingSoon'; -import { About } from 'features/help'; -import { Home } from 'features/home'; -import { Login } from 'features/login'; -import { Manifest } from 'features/manifest'; -import { Notifications } from 'features/notifications'; -import { Profile } from 'features/profile'; -import { Sites } from 'features/haztrakSite'; import React, { ReactElement, useEffect } from 'react'; -import { Button, Container } from 'react-bootstrap'; -import { Route, Routes, useNavigate } from 'react-router-dom'; +import { RouterProvider, useNavigate } from 'react-router-dom'; +import { router } from 'routes'; import { useAppDispatch, useAppSelector } from 'store'; -import './App.scss'; -import { getProfile } from 'store/rcraProfileSlice'; -import { selectRcraProfile } from 'store/rcraProfileSlice'; +import { getProfile, selectRcraProfile } from 'store/rcraProfileSlice'; import { selectUserName } from 'store/userSlice'; import { getHaztrakUser } from 'store/userSlice/user.slice'; +import './App.scss'; function App(): ReactElement { const userName = useAppSelector(selectUserName); const profile = useAppSelector(selectRcraProfile); - const navigate = useNavigate(); const dispatch = useAppDispatch(); useEffect(() => { @@ -34,77 +21,9 @@ function App(): ReactElement { }, [profile.user]); return ( -
- -
- - - - - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - - - - } - /> - } /> - } /> - } /> - {/* If unknown route, display 404*/} - - - -

404

-

Resource not found

-
- - - - - } - /> -
-
-
-
-
+ + + ); } diff --git a/client/src/components/Ht/HtCard/HtCard.tsx b/client/src/components/Ht/HtCard/HtCard.tsx index f4696fff3..7f64deeed 100644 --- a/client/src/components/Ht/HtCard/HtCard.tsx +++ b/client/src/components/Ht/HtCard/HtCard.tsx @@ -1,9 +1,9 @@ import { ErrorBoundary } from 'components/ErrorBoundary'; import { HtSpinner } from 'components/Ht'; import React, { ReactElement } from 'react'; -import { Card, CardProps } from 'react-bootstrap'; +import { Card, CardHeaderProps, CardProps } from 'react-bootstrap'; -interface HeaderProps extends CardProps { +interface HeaderProps extends CardHeaderProps { title?: string; size?: string; } diff --git a/client/src/components/PrivateRoute/PrivateRoute.tsx b/client/src/components/Layout/PrivateRoute.tsx similarity index 69% rename from client/src/components/PrivateRoute/PrivateRoute.tsx rename to client/src/components/Layout/PrivateRoute.tsx index f17276a9b..34c6a719b 100644 --- a/client/src/components/PrivateRoute/PrivateRoute.tsx +++ b/client/src/components/Layout/PrivateRoute.tsx @@ -1,9 +1,10 @@ import React, { ReactElement } from 'react'; import { Navigate } from 'react-router-dom'; +import { useAppSelector } from 'store'; +import { selectUserName } from 'store/userSlice'; interface Props { children: any; - authUser: string | undefined; } /** @@ -11,7 +12,8 @@ interface Props { * @param { children } Route to wrap around * @constructor */ -export function PrivateRoute({ children, authUser }: Props): ReactElement { +export function PrivateRoute({ children }: Props): ReactElement { + const authUser = useAppSelector(selectUserName); if (!authUser) { // not logged in so redirect to login page with the return url return ; diff --git a/client/src/components/Layout/Root.tsx b/client/src/components/Layout/Root.tsx new file mode 100644 index 000000000..23fc7e258 --- /dev/null +++ b/client/src/components/Layout/Root.tsx @@ -0,0 +1,25 @@ +import { ErrorBoundary } from 'components/ErrorBoundary'; +import { Sidebar } from './Sidebar'; +import { TopNav } from './TopNav'; +import { PrivateRoute } from './PrivateRoute'; +import React from 'react'; +import { Container } from 'react-bootstrap'; +import { Outlet } from 'react-router-dom'; + +export function Root() { + return ( +
+ + +
+ + + + + + +
+
+
+ ); +} diff --git a/client/src/components/Nav/SideBarNavItem.tsx b/client/src/components/Layout/SideBarNavItem.tsx similarity index 100% rename from client/src/components/Nav/SideBarNavItem.tsx rename to client/src/components/Layout/SideBarNavItem.tsx diff --git a/client/src/components/Nav/Sidebar.spec.tsx b/client/src/components/Layout/Sidebar.spec.tsx similarity index 94% rename from client/src/components/Nav/Sidebar.spec.tsx rename to client/src/components/Layout/Sidebar.spec.tsx index a29864740..fba1873da 100644 --- a/client/src/components/Nav/Sidebar.spec.tsx +++ b/client/src/components/Layout/Sidebar.spec.tsx @@ -1,5 +1,5 @@ import '@testing-library/jest-dom'; -import { Sidebar } from 'components/Nav'; +import { Sidebar } from 'components/Layout'; import React from 'react'; import { cleanup, renderWithProviders, screen } from 'test-utils'; import { afterEach, describe, expect, test } from 'vitest'; diff --git a/client/src/components/Nav/Sidebar.tsx b/client/src/components/Layout/Sidebar.tsx similarity index 100% rename from client/src/components/Nav/Sidebar.tsx rename to client/src/components/Layout/Sidebar.tsx diff --git a/client/src/components/Nav/TopNav.spec.tsx b/client/src/components/Layout/TopNav.spec.tsx similarity index 94% rename from client/src/components/Nav/TopNav.spec.tsx rename to client/src/components/Layout/TopNav.spec.tsx index 0780a0b28..2cffc3d32 100644 --- a/client/src/components/Nav/TopNav.spec.tsx +++ b/client/src/components/Layout/TopNav.spec.tsx @@ -1,5 +1,5 @@ import '@testing-library/jest-dom'; -import { TopNav } from 'components/Nav'; +import { TopNav } from 'components/Layout'; import React from 'react'; import { cleanup, renderWithProviders, screen } from 'test-utils'; import { afterEach, describe, expect, test } from 'vitest'; diff --git a/client/src/components/Nav/TopNav.tsx b/client/src/components/Layout/TopNav.tsx similarity index 100% rename from client/src/components/Nav/TopNav.tsx rename to client/src/components/Layout/TopNav.tsx diff --git a/client/src/components/Nav/index.ts b/client/src/components/Layout/index.ts similarity index 100% rename from client/src/components/Nav/index.ts rename to client/src/components/Layout/index.ts diff --git a/client/src/components/PrivateRoute/index.ts b/client/src/components/PrivateRoute/index.ts deleted file mode 100644 index d4b1c449c..000000000 --- a/client/src/components/PrivateRoute/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { PrivateRoute } from './PrivateRoute'; - -export { PrivateRoute }; diff --git a/client/src/env.d.ts b/client/src/env.d.ts index 8c41b3371..6a69e44ed 100644 --- a/client/src/env.d.ts +++ b/client/src/env.d.ts @@ -1,6 +1,11 @@ /// + +// see Vite's documentation on environment variables +// https://vitejs.dev/guide/env-and-mode.html#intellisense-for-typescript + interface ImportMetaEnv { readonly VITE_HT_API_URL: string; + // more env variables... } interface ImportMeta { diff --git a/client/src/features/404/NotFound.tsx b/client/src/features/404/NotFound.tsx new file mode 100644 index 000000000..e217aaf73 --- /dev/null +++ b/client/src/features/404/NotFound.tsx @@ -0,0 +1,22 @@ +import happyRobot from '/static/robot-bad-sign.jpg'; +import { HtCard } from 'components/Ht'; +import React from 'react'; +import { Button } from 'react-bootstrap'; +import { useNavigate } from 'react-router-dom'; + +export const NotFound = () => { + const navigate = useNavigate(); + return ( + + + + happy robot +

404

+

Resource not found

+
+ + + +
+ ); +}; diff --git a/client/src/features/404/index.ts b/client/src/features/404/index.ts new file mode 100644 index 000000000..448588323 --- /dev/null +++ b/client/src/features/404/index.ts @@ -0,0 +1,3 @@ +import { NotFound as Component } from './NotFound'; + +export { Component }; diff --git a/client/src/features/haztrakSite/SiteDetails/SiteDetails.tsx b/client/src/features/SiteDetails/SiteDetails.tsx similarity index 100% rename from client/src/features/haztrakSite/SiteDetails/SiteDetails.tsx rename to client/src/features/SiteDetails/SiteDetails.tsx diff --git a/client/src/features/SiteDetails/index.ts b/client/src/features/SiteDetails/index.ts new file mode 100644 index 000000000..44d601e4a --- /dev/null +++ b/client/src/features/SiteDetails/index.ts @@ -0,0 +1,3 @@ +import { SiteDetails as Component } from 'features/SiteDetails/SiteDetails'; + +export { Component }; diff --git a/client/src/features/haztrakSite/SiteList/SiteList.spec.tsx b/client/src/features/SiteList/SiteList.spec.tsx similarity index 95% rename from client/src/features/haztrakSite/SiteList/SiteList.spec.tsx rename to client/src/features/SiteList/SiteList.spec.tsx index c972f925e..2c39e3440 100644 --- a/client/src/features/haztrakSite/SiteList/SiteList.spec.tsx +++ b/client/src/features/SiteList/SiteList.spec.tsx @@ -1,4 +1,4 @@ -import { SiteList } from 'features/haztrakSite/SiteList'; +import { SiteList } from './SiteList'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import React from 'react'; diff --git a/client/src/features/haztrakSite/SiteList/SiteList.tsx b/client/src/features/SiteList/SiteList.tsx similarity index 100% rename from client/src/features/haztrakSite/SiteList/SiteList.tsx rename to client/src/features/SiteList/SiteList.tsx diff --git a/client/src/features/SiteList/index.ts b/client/src/features/SiteList/index.ts new file mode 100644 index 000000000..a6875fe77 --- /dev/null +++ b/client/src/features/SiteList/index.ts @@ -0,0 +1,3 @@ +import { SiteList as Component } from 'features/SiteList/SiteList'; + +export { Component }; diff --git a/client/src/features/comingSoon/UnderConstruction.tsx b/client/src/features/comingSoon/UnderConstruction.tsx index e591fc2a5..d2ac3cdbc 100644 --- a/client/src/features/comingSoon/UnderConstruction.tsx +++ b/client/src/features/comingSoon/UnderConstruction.tsx @@ -1,8 +1,8 @@ +import underConstruction from '/static/under-construction.png'; import { HtCard } from 'components/Ht'; +import { useTitle } from 'hooks'; import React from 'react'; import { Card, Col, Container, Row } from 'react-bootstrap'; -import { useTitle } from 'hooks'; -import underConstruction from '/under-construction.png'; import { Link } from 'react-router-dom'; /** diff --git a/client/src/features/comingSoon/index.ts b/client/src/features/comingSoon/index.ts index a044a3261..df8051a57 100644 --- a/client/src/features/comingSoon/index.ts +++ b/client/src/features/comingSoon/index.ts @@ -1,3 +1,3 @@ -import { UnderConstruction } from 'features/comingSoon/UnderConstruction'; +import { UnderConstruction as Component } from 'features/comingSoon/UnderConstruction'; -export { UnderConstruction }; +export { Component }; diff --git a/client/src/features/haztrakSite/SiteDetails/index.ts b/client/src/features/haztrakSite/SiteDetails/index.ts deleted file mode 100644 index bc912e52f..000000000 --- a/client/src/features/haztrakSite/SiteDetails/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { SiteDetails } from './SiteDetails'; - -export { SiteDetails }; diff --git a/client/src/features/haztrakSite/SiteList/index.ts b/client/src/features/haztrakSite/SiteList/index.ts deleted file mode 100644 index 63257103c..000000000 --- a/client/src/features/haztrakSite/SiteList/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { SiteList } from './SiteList'; - -export { SiteList }; diff --git a/client/src/features/haztrakSite/Sites.tsx b/client/src/features/haztrakSite/Sites.tsx deleted file mode 100644 index b9587eb4b..000000000 --- a/client/src/features/haztrakSite/Sites.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { Manifest } from 'features/manifest'; -import React, { ReactElement } from 'react'; -import { Route, Routes } from 'react-router-dom'; -import { SiteList } from './SiteList'; -import { SiteDetails } from './SiteDetails'; - -interface Props { - user: string; -} - -/** - * Request and display a list of site a user has access to - * @constructor - */ -export function Sites({ user }: Props): ReactElement { - return ( - <> - - } /> - } /> - } /> - - - ); -} diff --git a/client/src/features/haztrakSite/index.ts b/client/src/features/haztrakSite/index.ts deleted file mode 100644 index a124104cd..000000000 --- a/client/src/features/haztrakSite/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Sites } from './Sites'; - -export { Sites }; diff --git a/client/src/features/help/index.ts b/client/src/features/help/index.ts index bd77aa0c4..382974cdd 100644 --- a/client/src/features/help/index.ts +++ b/client/src/features/help/index.ts @@ -1,3 +1,3 @@ -import { About } from './About'; +import { About as Component } from './About'; -export { About }; +export { Component }; diff --git a/client/src/features/home/Home.spec.tsx b/client/src/features/home/Home.spec.tsx index 9c42f1f6b..4a229a16d 100644 --- a/client/src/features/home/Home.spec.tsx +++ b/client/src/features/home/Home.spec.tsx @@ -1,5 +1,5 @@ import '@testing-library/jest-dom'; -import { Home } from 'features/home'; +import { Home } from './Home'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import React from 'react'; diff --git a/client/src/features/home/index.ts b/client/src/features/home/index.ts index 646ca1197..fb3469c98 100644 --- a/client/src/features/home/index.ts +++ b/client/src/features/home/index.ts @@ -1,3 +1,3 @@ -import { Home } from './Home'; +import { Home as Component } from './Home'; -export { Home }; +export { Component }; diff --git a/client/src/features/login/Login.tsx b/client/src/features/login/Login.tsx index 46379ac32..0bb7f583c 100644 --- a/client/src/features/login/Login.tsx +++ b/client/src/features/login/Login.tsx @@ -44,9 +44,9 @@ export function Login(): ReactElement { } return ( - - - + + + haztrak logo, hazardous waste tracking made easy. - - } /> - } /> - } /> - - - ); -} diff --git a/client/src/features/manifest/index.ts b/client/src/features/manifest/index.ts deleted file mode 100644 index 8795ad980..000000000 --- a/client/src/features/manifest/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Manifest } from './Manifest'; - -export { Manifest }; diff --git a/client/src/features/manifest/ManifestDetails.tsx b/client/src/features/manifestDetails/ManifestDetails.tsx similarity index 100% rename from client/src/features/manifest/ManifestDetails.tsx rename to client/src/features/manifestDetails/ManifestDetails.tsx diff --git a/client/src/features/manifestDetails/index.ts b/client/src/features/manifestDetails/index.ts new file mode 100644 index 000000000..d178fe0df --- /dev/null +++ b/client/src/features/manifestDetails/index.ts @@ -0,0 +1,3 @@ +import { ManifestDetails as Component } from './ManifestDetails'; + +export { Component }; diff --git a/client/src/features/manifest/ManifestList.tsx b/client/src/features/manifestList/ManifestList.tsx similarity index 97% rename from client/src/features/manifest/ManifestList.tsx rename to client/src/features/manifestList/ManifestList.tsx index 86b0b7f5b..3ee5e4e08 100644 --- a/client/src/features/manifest/ManifestList.tsx +++ b/client/src/features/manifestList/ManifestList.tsx @@ -29,7 +29,7 @@ export function ManifestList(): ReactElement { } return ( - <> + @@ -57,6 +57,6 @@ export function ManifestList(): ReactElement { - + ); } diff --git a/client/src/features/manifest/NewManifest.spec.tsx b/client/src/features/manifestList/NewManifest.spec.tsx similarity index 96% rename from client/src/features/manifest/NewManifest.spec.tsx rename to client/src/features/manifestList/NewManifest.spec.tsx index 643c263e4..841619ec2 100644 --- a/client/src/features/manifest/NewManifest.spec.tsx +++ b/client/src/features/manifestList/NewManifest.spec.tsx @@ -1,6 +1,6 @@ import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; -import { NewManifest } from 'features/manifest/NewManifest'; +import { NewManifest } from 'features/newManifest/NewManifest'; import React from 'react'; import { renderWithProviders, screen } from 'test-utils'; import { createMockPermission, createMockSite } from 'test-utils/fixtures/mockHandler'; diff --git a/client/src/features/manifestList/index.ts b/client/src/features/manifestList/index.ts new file mode 100644 index 000000000..f4d15a598 --- /dev/null +++ b/client/src/features/manifestList/index.ts @@ -0,0 +1,3 @@ +import { ManifestList as Component } from './ManifestList'; + +export { Component }; diff --git a/client/src/features/manifest/NewManifest.tsx b/client/src/features/newManifest/NewManifest.tsx similarity index 100% rename from client/src/features/manifest/NewManifest.tsx rename to client/src/features/newManifest/NewManifest.tsx diff --git a/client/src/features/newManifest/index.ts b/client/src/features/newManifest/index.ts new file mode 100644 index 000000000..0021eae40 --- /dev/null +++ b/client/src/features/newManifest/index.ts @@ -0,0 +1,3 @@ +import { NewManifest as Component } from './NewManifest'; + +export { Component }; diff --git a/client/src/features/notifications/index.ts b/client/src/features/notifications/index.ts index 9664d91f9..fb0e7538d 100644 --- a/client/src/features/notifications/index.ts +++ b/client/src/features/notifications/index.ts @@ -1,3 +1,3 @@ -import { Notifications } from './Notifications'; +import { Notifications as Component } from './Notifications'; -export { Notifications }; +export { Component }; diff --git a/client/src/features/profile/index.ts b/client/src/features/profile/index.ts index ee4ac24c0..6bd2c36cd 100644 --- a/client/src/features/profile/index.ts +++ b/client/src/features/profile/index.ts @@ -1,3 +1,3 @@ -import { Profile } from './Profile'; +import { Profile as Component } from './Profile'; -export { Profile }; +export { Component }; diff --git a/client/src/index.tsx b/client/src/index.tsx index 20fc4fd02..cbc252b91 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -18,9 +18,7 @@ if (import.meta.env.VITE_HT_ENV && import.meta.env.VITE_HT_ENV.toUpperCase() === root.render( - - - + ); diff --git a/client/src/routes.tsx b/client/src/routes.tsx new file mode 100644 index 000000000..73cde6d53 --- /dev/null +++ b/client/src/routes.tsx @@ -0,0 +1,89 @@ +import { Root } from 'components/Layout/Root'; +import { Login } from 'features/login'; +import { createBrowserRouter } from 'react-router-dom'; + +export const router = createBrowserRouter([ + { + path: '/', + element: , + children: [ + { + path: '', + lazy: () => import('./features/home'), + }, + { + path: '/notifications', + lazy: () => import('./features/notifications'), + }, + { + path: '/profile', + lazy: () => import('./features/profile'), + }, + { + path: '/site', + children: [ + { + path: '', + // element: , + lazy: () => import('./features/SiteList'), + }, + { + path: ':siteId', + // element: , + lazy: () => import('./features/SiteDetails'), + }, + { + path: ':siteId/manifest', + children: [ + { + path: '', + lazy: () => import('./features/manifestList'), + }, + { + path: 'new', + lazy: () => import('./features/newManifest'), + }, + { + path: ':mtn/:action', + lazy: () => import('./features/manifestDetails'), + }, + ], + }, + ], + }, + { + path: '/manifest', + children: [ + { + path: '', + lazy: () => import('./features/manifestList'), + }, + { + path: 'new', + lazy: () => import('./features/newManifest'), + }, + { + path: ':mtn/:action', + lazy: () => import('./features/manifestDetails'), + }, + ], + }, + { + path: '/about', + lazy: () => import('./features/help'), + }, + { + path: '/coming-soon', + lazy: () => import('./features/comingSoon'), + }, + { + path: '*', + lazy: () => import('./features/404'), + }, + ], + }, + { + path: '/login', + element: , + }, +]); diff --git a/client/vite.config.ts b/client/vite.config.ts index a36ebd29e..ee2027118 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -3,13 +3,33 @@ import react from '@vitejs/plugin-react'; import { defineConfig } from 'vite'; import eslint from 'vite-plugin-eslint'; import viteTsconfigPaths from 'vite-tsconfig-paths'; +// @ts-ignore +import { dependencies } from './package.json'; + +function renderChunks(deps: Record) { + const chunks = {}; + Object.keys(deps).forEach((key) => { + if (['react', 'react-router-dom', 'react-dom'].includes(key)) return; + // @ts-ignore + chunks[key] = [key]; + }); + return chunks; +} // https://vitejs.dev/config/ export default defineConfig({ build: { sourcemap: true, outDir: 'build', - chunkSizeWarningLimit: 1000, + chunkSizeWarningLimit: 500, + rollupOptions: { + output: { + manualChunks: { + vendor: ['react', 'react-router-dom', 'react-dom'], + ...renderChunks(dependencies), + }, + }, + }, }, plugins: [react(), viteTsconfigPaths(), eslint()], server: {