From 92ff8f71eb2da7a6e3ea692c98079368fb45c296 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 17 Jul 2022 13:54:34 +0200 Subject: [PATCH] Create custom getFetchUrl for react query SSR --- front/next.config.js | 26 ++++++++++ front/package.json | 3 +- front/src/pages/_app.tsx | 28 ++++++++-- front/src/pages/index.tsx | 3 +- front/src/pages/toto.tsx | 19 +++++-- front/src/utils/link.tsx | 4 +- front/src/utils/query.ts | 70 +++++++++++++++++++++++++ front/yarn.lock | 92 ++++++++++++++++++++++++++++++++- src/Kyoo.WebApp/WebAppModule.cs | 2 +- 9 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 front/src/utils/query.ts diff --git a/front/next.config.js b/front/next.config.js index 6fba841d..6c813fc2 100755 --- a/front/next.config.js +++ b/front/next.config.js @@ -1,9 +1,35 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + /** * @type {import("next").NextConfig} */ const nextConfig = { reactStrictMode: true, swcMinify: true, + env: { + KYOO_URL: process.env.KYOO_URL ?? "http://localhost:5000", + }, + rewrites: async () => [ + { source: "/api/:path*", destination: process.env.KYOO_URL ?? "http://localhost:5000/:path*" }, + ], }; module.exports = nextConfig; diff --git a/front/package.json b/front/package.json index f513f757..535d578f 100644 --- a/front/package.json +++ b/front/package.json @@ -27,7 +27,8 @@ "@mui/material": "^5.8.7", "next": "12.2.2", "react": "18.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "react-query": "^4.0.0-beta.23" }, "devDependencies": { "@types/node": "18.0.3", diff --git a/front/src/pages/_app.tsx b/front/src/pages/_app.tsx index f4170a2e..bf4d3c28 100755 --- a/front/src/pages/_app.tsx +++ b/front/src/pages/_app.tsx @@ -19,15 +19,33 @@ */ import { ThemeProvider } from "@mui/material"; +import NextApp, { AppContext } from "next/app"; import type { AppProps } from "next/app"; +import { Hydrate, QueryClientProvider } from "react-query"; +import { createQueryClient, fetchQuery } from "~/utils/query"; import { defaultTheme } from "~/utils/themes/default-theme"; +import { useState } from "react"; -const MyApp = ({ Component, pageProps }: AppProps) => { +const App = ({ Component, pageProps }: AppProps) => { + const [queryClient] = useState(() => createQueryClient()); return ( - - - + + + + + + + ); }; -export default MyApp; +App.getInitialProps = async (ctx: AppContext) => { + const appProps = await NextApp.getInitialProps(ctx); + + const getUrl = (ctx.Component as any).getFetchUrls; + if (getUrl) appProps.pageProps.queryState = await fetchQuery(getUrl(ctx.router.query)); + + return appProps; +}; + +export default App; diff --git a/front/src/pages/index.tsx b/front/src/pages/index.tsx index efc1262c..a25e391a 100755 --- a/front/src/pages/index.tsx +++ b/front/src/pages/index.tsx @@ -20,7 +20,8 @@ import type { NextPage } from "next"; import { Stack, Button } from "@mui/material"; -import Link from "~/utils/link"; +import Link from "next/link"; +// import { Link } from "~/utils/link"; const Home: NextPage = () => { return ( diff --git a/front/src/pages/toto.tsx b/front/src/pages/toto.tsx index 10aafaa0..d150bb22 100644 --- a/front/src/pages/toto.tsx +++ b/front/src/pages/toto.tsx @@ -18,12 +18,25 @@ * along with Kyoo. If not, see . */ -import type { NextPage } from "next"; +import { QueryPage, useFetch } from "~/utils/query"; -const Toto: NextPage = () => { +const Toto: QueryPage = ({}) => { + const libraries = useFetch("libraries"); + + if (libraries.error) return

oups

; + if (!libraries.data) return

loading

; + + console.log(libraries.data.items); return ( -

toto

+ <> +

toto

+ {libraries.data.items.map((x: any) => ( +

{x.name}

+ ))} + ); }; +Toto.getFetchUrls = () => [["libraries"]]; + export default Toto; diff --git a/front/src/utils/link.tsx b/front/src/utils/link.tsx index ed670c05..37ee297f 100644 --- a/front/src/utils/link.tsx +++ b/front/src/utils/link.tsx @@ -70,7 +70,7 @@ export type LinkProps = { // A styled version of the Next.js Link component: // https://nextjs.org/docs/api-reference/next/link -const Link = React.forwardRef(function Link(props, ref) { +export const Link = React.forwardRef(function Link(props, ref) { const { activeClassName = "active", as, @@ -121,5 +121,3 @@ const Link = React.forwardRef(function Link(props, /> ); }); - -export default Link; diff --git a/front/src/utils/query.ts b/front/src/utils/query.ts new file mode 100644 index 00000000..31b0b198 --- /dev/null +++ b/front/src/utils/query.ts @@ -0,0 +1,70 @@ +/* + * Kyoo - A portable and vast media library solution. + * Copyright (c) Kyoo. + * + * See AUTHORS.md and LICENSE file in the project root for full license information. + * + * Kyoo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * Kyoo 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Kyoo. If not, see . + */ + +import { ComponentType } from "react"; +import { dehydrate, QueryClient, QueryFunctionContext, useQuery } from "react-query"; + +const isServer = () => typeof window === "undefined" + +const queryFn = async (context: QueryFunctionContext): Promise => { + try { + const resp = await fetch( + [isServer() ? process.env.KYOO_URL : "/api"] + .concat(context.pageParam ? [context.pageParam] : (context.queryKey as string[])) + .join("/"), + ); + if (!resp.ok) { + throw await resp.json(); + } + return await resp.json(); + } catch (e) { + console.error(e); + throw { errors: ["Could not reach Kyoo's server."] }; // as KyooErrors; + } +}; + +export const createQueryClient = () => + new QueryClient({ + defaultOptions: { + queries: { + staleTime: Infinity, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + retry: false, + queryFn: queryFn, + }, + }, + }); + +export type QueryPage = ComponentType & { + getFetchUrls?: (route: { [key: string]: string }) => [[string]]; +}; + +export const useFetch = (...params: [string]) => { + return useQuery(params); +}; + +export const fetchQuery = async (queries: [[string]]) => { + if (!isServer()) return {}; + + const client = createQueryClient(); + await Promise.all(queries.map((x) => client.prefetchQuery(x))); + return dehydrate(client); +}; diff --git a/front/yarn.lock b/front/yarn.lock index abba3dc9..43b69ea5 100644 --- a/front/yarn.lock +++ b/front/yarn.lock @@ -50,7 +50,7 @@ core-js-pure "^3.20.2" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.10.2", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.2", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.2", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.6.tgz#6a1ef59f838debd670421f8c7f2cbb8da9751580" integrity sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ== @@ -476,6 +476,11 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/use-sync-external-store@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43" + integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA== + "@typescript-eslint/parser@^5.21.0": version "5.30.6" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.30.6.tgz#add440db038fa9d777e4ebdaf66da9e7fb7abe92" @@ -637,6 +642,11 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +big-integer@^1.6.16: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + binary-searching@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/binary-searching/-/binary-searching-2.0.5.tgz#ab6d08d51cd1b58878ae208ab61988f885b22dd3" @@ -657,6 +667,20 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -824,6 +848,11 @@ dequal@^2.0.0: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== +detect-node@^2.0.4, detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + diff@^5.0.0: version "5.1.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" @@ -1512,6 +1541,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -1611,6 +1645,14 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + mdast-util-from-markdown@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" @@ -1842,6 +1884,11 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1874,6 +1921,13 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA== + dependencies: + big-integer "^1.6.16" + nanoid@^3.1.30: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" @@ -1970,6 +2024,11 @@ object.values@^1.1.5: define-properties "^1.1.3" es-abstract "^1.19.1" +oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -2125,6 +2184,17 @@ react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-query@^4.0.0-beta.23: + version "4.0.0-beta.23" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-4.0.0-beta.23.tgz#76713547670ef1f991ae828b3d51df63ec6e035c" + integrity sha512-e6mNBVAYGy0M1OwX0mhRB/lCkOedKeqTUrbPjNCqvm8hQGUsJJobqfHVvTv8o6JJaOO2MFcxKF4vZM+PEKbHZA== + dependencies: + "@babel/runtime" "^7.17.9" + "@types/use-sync-external-store" "^0.0.3" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + use-sync-external-store "^1.1.0" + react-transition-group@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" @@ -2161,6 +2231,11 @@ regexpp@^3.2.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -2189,7 +2264,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: +rimraf@3.0.2, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2426,6 +2501,14 @@ unist-util-stringify-position@^3.0.0: dependencies: "@types/unist" "^2.0.0" +unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -2438,6 +2521,11 @@ use-sync-external-store@1.1.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz#3343c3fe7f7e404db70f8c687adf5c1652d34e82" integrity sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ== +use-sync-external-store@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" + integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== + uvu@^0.5.0: version "0.5.6" resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.6.tgz#2754ca20bcb0bb59b64e9985e84d2e81058502df" diff --git a/src/Kyoo.WebApp/WebAppModule.cs b/src/Kyoo.WebApp/WebAppModule.cs index 8fbf76b5..349f6f48 100644 --- a/src/Kyoo.WebApp/WebAppModule.cs +++ b/src/Kyoo.WebApp/WebAppModule.cs @@ -50,7 +50,7 @@ namespace Kyoo.WebApp public Dictionary Configuration => new(); /// - public bool Enabled => Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot")); + public bool Enabled => false; // Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot")); /// /// Create a new .