diff --git a/package.json b/package.json index 0da1a36..2e9786c 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@loadable/webpack-plugin": "^5.15.2", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.4", "@types/compression": "^1.7.0", + "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.10", "@types/express": "^4.17.11", "@types/express-session": "^1.17.3", diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index 6fbd8a5..313ac5f 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -2,10 +2,11 @@ import { Outlet } from "react-router"; import { Header } from "./Header"; import { Footer } from "./Footer"; +import type { PreLoadComponentType } from "types/components"; import style from "./index.module.scss"; -export const Layout = () => { +export const Layout: PreLoadComponentType = () => { return (
diff --git a/src/components/LoadingBar/index.tsx b/src/components/LoadingBar/index.tsx index 7620a78..140c707 100644 --- a/src/components/LoadingBar/index.tsx +++ b/src/components/LoadingBar/index.tsx @@ -1,11 +1,11 @@ import { useEffect, useState } from "react"; -import { useChangeLoadingWithoutRedux, useLoadingBar } from "hooks/useLoadingBar"; +import { useLoadingBar, useLoadingBarState } from "hooks/useLoadingBar"; import { Bar } from "./LoadingBar"; import type { LoadingBarWrapperType } from "types/components"; export const LoadingBar: LoadingBarWrapperType = () => { const [loading, setLoading] = useState(false); - const loadingState = useChangeLoadingWithoutRedux((s) => s.loading); + const loadingState = useLoadingBarState((s) => s.loading); useEffect(() => { let id: NodeJS.Timeout | null = null; if (loadingState) { diff --git a/src/hooks/useLang.ts b/src/hooks/useLang.ts index f3b87b7..4083d50 100644 --- a/src/hooks/useLang.ts +++ b/src/hooks/useLang.ts @@ -1,17 +1,14 @@ import { apiName } from "config/api"; -import shallow from "zustand/shallow"; import { useCallback, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; +import cookie from "js-cookie"; import { useChangeLoadingWithoutRedux } from "./useLoadingBar"; import { getDataAction_Server } from "store/reducer/server/share/action"; import type { StoreState } from "types/store"; export const useLang = () => { const lang = useSelector((state) => state.client.currentLang.data); - const { start, end } = useChangeLoadingWithoutRedux( - useCallback((s) => ({ start: s.start, end: s.end }), []), - shallow - ); + const { start, end } = useChangeLoadingWithoutRedux(); const langRef = useRef(lang); const dispatch = useDispatch(); langRef.current = lang; @@ -19,7 +16,10 @@ export const useLang = () => { (newLang: string) => { if (langRef.current !== newLang) { Promise.resolve(start()) - .then(() => dispatch(getDataAction_Server({ name: apiName.lang, lang: newLang }))) + .then(() => { + cookie.set("site_lang", newLang); + return dispatch(getDataAction_Server({ name: apiName.lang, lang: newLang })); + }) .then(end) .catch(end); } diff --git a/src/hooks/useLoadingBar.ts b/src/hooks/useLoadingBar.ts index 9cc3db0..ca1a6b2 100644 --- a/src/hooks/useLoadingBar.ts +++ b/src/hooks/useLoadingBar.ts @@ -4,6 +4,7 @@ import { useDispatch } from "react-redux"; import { actionName } from "config/action"; import { setDataSuccess_client } from "store/reducer/client/share/action"; import { delay, cancel } from "utils/delay"; +import shallow from "zustand/shallow"; type LoadingBarProps = { height?: number; @@ -59,7 +60,7 @@ const useLoadingBar = (props: LoadingBarProps = {}) => { return { ref }; }; -const useChangeLoadingWithoutRedux = create<{ loading: boolean; start: () => void; end: () => void }>((set) => ({ +const useLoadingBarState = create<{ loading: boolean; start: () => void; end: () => void }>((set) => ({ loading: false, start: () => set({ loading: true }), end: () => set({ loading: false }), @@ -73,4 +74,11 @@ const useChangeLoading = () => { return { start, end }; }; -export { useLoadingBar, useChangeLoading, useChangeLoadingWithoutRedux }; +const useChangeLoadingWithoutRedux = () => { + return useLoadingBarState( + useCallback((s) => ({ start: s.start, end: s.end }), []), + shallow + ); +}; + +export { useLoadingBar, useChangeLoading, useLoadingBarState, useChangeLoadingWithoutRedux }; diff --git a/src/hooks/usePreLoad.ts b/src/hooks/usePreLoad.ts index 6563698..6c9cc69 100644 --- a/src/hooks/usePreLoad.ts +++ b/src/hooks/usePreLoad.ts @@ -1,7 +1,6 @@ -import { useCallback, useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useStore } from "react-redux"; import cookie from "js-cookie"; -import shallow from "zustand/shallow"; import { useLocation, useNavigate } from "react-router"; import { log } from "utils/log"; import { useChangeLoadingWithoutRedux } from "./useLoadingBar"; @@ -13,10 +12,7 @@ const usePreLoad: UsePreLoadType = ({ routes, preLoad }) => { const store = useStore(); const location = useLocation(); const navigate = useNavigate(); - const { start, end } = useChangeLoadingWithoutRedux( - useCallback((s) => ({ start: s.start, end: s.end }), []), - shallow - ); + const { start, end } = useChangeLoadingWithoutRedux(); const firstLoad = useRef(true); const loadedPath = useRef(""); const loadingPath = useRef(""); diff --git a/src/server/middleware/renderPage/middleware/initLang.ts b/src/server/middleware/renderPage/middleware/initLang.ts index db8b0a2..57506ba 100644 --- a/src/server/middleware/renderPage/middleware/initLang.ts +++ b/src/server/middleware/renderPage/middleware/initLang.ts @@ -2,8 +2,11 @@ import { determineUserLang } from "utils/i18n"; import { Middleware } from "../compose"; export const initLang: Middleware = (next) => async (args) => { - const { req } = args; - const lang = determineUserLang(req.acceptsLanguages(), req.path); + const { req, res } = args; + const cookieLang = req.cookies?.site_lang; + const lang = cookieLang || determineUserLang(req.acceptsLanguages(), req.path); + + res.cookie("site_lang", lang); args.lang = lang; args.env && (args.env["LANG"] = lang); diff --git a/src/server/setup/index.ts b/src/server/setup/index.ts index ddbd702..ccb296d 100644 --- a/src/server/setup/index.ts +++ b/src/server/setup/index.ts @@ -1,4 +1,5 @@ import express, { Express } from "express"; +import cookieParser from "cookie-parser"; import cors from "cors"; import session from "express-session"; @@ -9,6 +10,8 @@ const setUp = (expressApp: Express) => { expressApp.use(express.static(`${process.cwd()}/dist`)); + expressApp.use(cookieParser()) + expressApp.use(express.json({ limit: "5mb" })); expressApp.use(express.urlencoded({ extended: true })); diff --git a/src/store/index.ts b/src/store/index.ts index 1ca0534..42684ee 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -13,7 +13,7 @@ type CreateStoreProps = { }; const devTools = - __CLIENT__ && typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === "function" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ actionsBlacklist: [] }); + __CLIENT__ && typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === "function" && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ actionsDenylist: [] }); const composeEnhancers = devTools || compose; diff --git a/yarn.lock b/yarn.lock index e9f9209..c4e699b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2158,6 +2158,13 @@ dependencies: "@types/node" "*" +"@types/cookie-parser@^1.4.2": + version "1.4.2" + resolved "https://registry.npmmirror.com/@types/cookie-parser/download/@types/cookie-parser-1.4.2.tgz#e4d5c5ffda82b80672a88a4281aaceefb1bd9df5" + integrity sha1-5NXF/9qCuAZyqIpCgarO77G9nfU= + dependencies: + "@types/express" "*" + "@types/cors@^2.8.10": version "2.8.12" resolved "https://registry.npmmirror.com/@types/cors/download/@types/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" @@ -3624,7 +3631,7 @@ convert-source-map@^1.1.0, convert-source-map@^1.5.0, convert-source-map@^1.7.0: cookie-parser@^1.4.6: version "1.4.6" resolved "https://registry.npmmirror.com/cookie-parser/download/cookie-parser-1.4.6.tgz#3ac3a7d35a7a03bbc7e365073a26074824214594" - integrity sha1-OsOn01p6A7vH42UHOiYHSCQhRZQ= + integrity sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA== dependencies: cookie "0.4.1" cookie-signature "1.0.6"