Skip to content

Commit e1a313e

Browse files
committed
Merge remote-tracking branch 'tik/dev'
2 parents 99a0747 + 812f809 commit e1a313e

12 files changed

Lines changed: 112 additions & 502 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 2.1.0-beta.3
4+
5+
**Bug fixes and improvements:**
6+
7+
- Enabled code splitting for the frontend, halving the initial page load from its previous size
8+
39
## 2.1.0-beta.2
410

511
**Bug fixes and improvements:**

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@
7070
},
7171
"overrides": {
7272
"react-final-form@6.5.9>react": "^19.2.0",
73-
"react-final-form-arrays@3.1.4>react": "^19.2.0"
73+
"react-final-form-arrays@3.1.4>react": "^19.2.0",
74+
"email-templates@*>preview-email": "0.0.0"
7475
}
7576
}
7677
}

packages/ilmomasiina-client/src/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ErrorCode } from "@tietokilta/ilmomasiina-models";
1+
import type { ErrorCode } from "@tietokilta/ilmomasiina-models";
22

33
export interface FetchOptions {
44
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React, { useCallback } from "react";
2+
3+
import { Button } from "react-bootstrap";
4+
import { useTranslation } from "react-i18next";
5+
import { useNavigate } from "react-router";
6+
7+
import { loginToast } from "../../modules/auth";
8+
import useStore from "../../modules/store";
9+
import paths from "../../paths";
10+
11+
export default function Logout() {
12+
const { loggedIn, resetAuth } = useStore((state) => state.auth);
13+
const navigate = useNavigate();
14+
const { t } = useTranslation();
15+
16+
const logout = useCallback(() => {
17+
resetAuth();
18+
loginToast("success", t("auth.logoutSuccess"), 2000);
19+
navigate(paths.adminLogin);
20+
}, [resetAuth, navigate, t]);
21+
22+
return loggedIn ? <Button onClick={logout}>{t("header.logout")}</Button> : null;
23+
}

packages/ilmomasiina-frontend/src/components/Header/index.tsx

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,25 @@
1-
import React, { useCallback } from "react";
1+
import React, { lazy, Suspense } from "react";
22

33
import { Button, Container, Navbar } from "react-bootstrap";
44
import { useTranslation } from "react-i18next";
5-
import { Link, useNavigate } from "react-router-dom";
5+
import { Link } from "react-router-dom";
66

77
import logo from "../../assets/logo.svg";
88
import branding from "../../branding";
99
import i18n from "../../i18n";
10-
import { loginToast } from "../../modules/auth";
11-
import useStore from "../../modules/store";
1210
import paths from "../../paths";
1311

1412
import "./Header.scss";
1513

14+
// Code-split Logout to avoid strong dependency on the store.
15+
const Logout = lazy(() => import("./Logout"));
16+
1617
const Header = () => {
17-
const { loggedIn, resetAuth } = useStore((state) => state.auth);
18-
const navigate = useNavigate();
1918
const {
2019
i18n: { language },
2120
t,
2221
} = useTranslation();
2322

24-
const logout = useCallback(() => {
25-
resetAuth();
26-
loginToast("success", i18n.t("auth.logoutSuccess"), 2000);
27-
navigate(paths.adminLogin);
28-
}, [resetAuth, navigate]);
29-
3023
return (
3124
<Navbar>
3225
<Container className="gap-sm-2">
@@ -41,7 +34,9 @@ const Header = () => {
4134
{language !== "en" && (
4235
<Button onClick={() => i18n.changeLanguage("en")}>{t("header.switchLanguage", { lng: "en" })}</Button>
4336
)}
44-
{loggedIn && <Button onClick={logout}>{t("header.logout")}</Button>}
37+
<Suspense>
38+
<Logout />
39+
</Suspense>
4540
</Container>
4641
</Navbar>
4742
);
Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,45 @@
1-
import React, { useEffect } from "react";
1+
import React, { lazy, Suspense } from "react";
22

3-
import { Container } from "react-bootstrap";
3+
import { Container, Spinner } from "react-bootstrap";
44
import { BrowserRouter, Route, Routes } from "react-router";
55
import { Flip, ToastContainer } from "react-toastify";
66

77
import Footer from "../components/Footer";
88
import Header from "../components/Header";
9-
import useStore from "../modules/store";
109
import paths from "../paths";
1110
import PageNotFound from "../routes/404/PageNotFound";
12-
import AdminEventsList from "../routes/AdminEventsList";
13-
import AdminUsersList from "../routes/AdminUsers";
14-
import AuditLog from "../routes/AuditLog";
15-
import Editor from "../routes/Editor";
16-
import EditSignup from "../routes/EditSignup";
17-
import EventList from "../routes/EventList";
18-
import InitialSetup from "../routes/InitialSetup";
19-
import Login from "../routes/Login";
20-
import SingleEvent from "../routes/SingleEvent";
2111

2212
import "react-toastify/dist/ReactToastify.css";
2313
import "../styles/app.scss";
2414

25-
const LOGIN_RENEW_INTERVAL = 60 * 1000;
15+
// Code-split route components.
16+
const AdminEventsList = lazy(() => import("../routes/AdminEventsList"));
17+
const AdminUsersList = lazy(() => import("../routes/AdminUsers"));
18+
const AuditLog = lazy(() => import("../routes/AuditLog"));
19+
const Editor = lazy(() => import("../routes/Editor"));
20+
const EditSignup = lazy(() => import("../routes/EditSignup"));
21+
const EventList = lazy(() => import("../routes/EventList"));
22+
const InitialSetup = lazy(() => import("../routes/InitialSetup"));
23+
const Login = lazy(() => import("../routes/Login"));
24+
const SingleEvent = lazy(() => import("../routes/SingleEvent"));
2625

27-
const AppContainer = () => {
28-
const renewLogin = useStore((state) => state.auth.renewLogin);
29-
useEffect(() => {
30-
// Renew login immediately on page load if necessary.
31-
renewLogin();
32-
// Then, check every minute and renew if necessary.
33-
const timer = window.setInterval(() => renewLogin(), LOGIN_RENEW_INTERVAL);
34-
return () => window.clearTimeout(timer);
35-
}, [renewLogin]);
26+
// Also code-split RenewLogin to avoid strong dependency on the store.
27+
const RenewLogin = lazy(() => import("./RenewLogin"));
3628

37-
return (
38-
<BrowserRouter>
39-
<div className="layout-wrapper">
40-
<Header />
29+
const loadingFallback = (
30+
<div className="ilmo--loading-container">
31+
<Spinner animation="border" />
32+
</div>
33+
);
34+
35+
const AppContainer = () => (
36+
<BrowserRouter>
37+
<Suspense>
38+
<RenewLogin />
39+
</Suspense>
40+
<div className="layout-wrapper">
41+
<Header />
42+
<Suspense fallback={loadingFallback}>
4143
<Container>
4244
<Routes>
4345
<Route path={paths.eventsList} element={<EventList />} />
@@ -53,22 +55,22 @@ const AppContainer = () => {
5355
<Route path="*" element={<PageNotFound />} />
5456
</Routes>
5557
</Container>
56-
<Footer />
57-
<ToastContainer
58-
position="top-right"
59-
autoClose={5000}
60-
hideProgressBar={false}
61-
newestOnTop={false}
62-
closeOnClick
63-
rtl={false}
64-
pauseOnFocusLoss
65-
draggable
66-
pauseOnHover
67-
transition={Flip}
68-
/>
69-
</div>
70-
</BrowserRouter>
71-
);
72-
};
58+
</Suspense>
59+
<Footer />
60+
<ToastContainer
61+
position="top-right"
62+
autoClose={5000}
63+
hideProgressBar={false}
64+
newestOnTop={false}
65+
closeOnClick
66+
rtl={false}
67+
pauseOnFocusLoss
68+
draggable
69+
pauseOnHover
70+
transition={Flip}
71+
/>
72+
</div>
73+
</BrowserRouter>
74+
);
7375

7476
export default AppContainer;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { useEffect } from "react";
2+
3+
import useStore from "../modules/store";
4+
5+
const LOGIN_RENEW_INTERVAL = 60 * 1000;
6+
7+
/** Auto-renews the auth token periodically while the page is active. */
8+
export default function RenewLogin() {
9+
const renewLogin = useStore((state) => state.auth.renewLogin);
10+
useEffect(() => {
11+
// Renew login immediately on page load if necessary.
12+
renewLogin();
13+
// Then, check every minute and renew if necessary.
14+
const timer = window.setInterval(() => renewLogin(), LOGIN_RENEW_INTERVAL);
15+
return () => window.clearInterval(timer);
16+
}, [renewLogin]);
17+
18+
return null;
19+
}

packages/ilmomasiina-frontend/src/i18n.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import i18n, { DefaultNamespace, ParseKeys } from "i18next";
22
import LanguageDetector from "i18next-browser-languagedetector";
33
import { initReactI18next } from "react-i18next";
44

5-
import { i18nResources as componentsRes } from "@tietokilta/ilmomasiina-client";
5+
// Import via full path to reduce entry chunk size.
6+
import { i18nResources as componentsRes } from "@tietokilta/ilmomasiina-client/dist/locales";
67
import en from "./locales/en.json";
78
import fi from "./locales/fi.json";
89

packages/ilmomasiina-frontend/src/index.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import ReactDOM from "react-dom/client";
55

66
import "./i18n";
77

8-
import { configureApi } from "@tietokilta/ilmomasiina-client";
8+
// Import via full path to reduce entry chunk size.
9+
import { configureApi } from "@tietokilta/ilmomasiina-client/dist/api";
910
import AppContainer from "./containers/AppContainer";
1011
import { apiUrl } from "./paths";
1112

packages/ilmomasiina-frontend/src/paths.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { EventID, EventSlug, SignupEditToken, SignupID } from "@tietokilta/ilmomasiina-models";
1+
import type { EventID, EventSlug, SignupEditToken, SignupID } from "@tietokilta/ilmomasiina-models";
22

33
export const urlPrefix = PATH_PREFIX;
44

0 commit comments

Comments
 (0)