Create custom getFetchUrl for react query SSR

This commit is contained in:
Zoe Roux 2022-07-17 13:54:34 +02:00
parent 86639629ee
commit 92ff8f71eb
9 changed files with 231 additions and 16 deletions

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
/**
* @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;

View File

@ -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",

View File

@ -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 (
<QueryClientProvider client={queryClient}>
<Hydrate state={pageProps.queryState}>
<ThemeProvider theme={defaultTheme}>
<Component {...pageProps} />
</ThemeProvider>
</Hydrate>
</QueryClientProvider>
);
};
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;

View File

@ -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 (

View File

@ -18,12 +18,25 @@
* along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
*/
import type { NextPage } from "next";
import { QueryPage, useFetch } from "~/utils/query";
const Toto: NextPage = () => {
const Toto: QueryPage = ({}) => {
const libraries = useFetch<any>("libraries");
if (libraries.error) return <p>oups</p>;
if (!libraries.data) return <p>loading</p>;
console.log(libraries.data.items);
return (
<>
<p>toto</p>
{libraries.data.items.map((x: any) => (
<p key={x.id}>{x.name}</p>
))}
</>
);
};
Toto.getFetchUrls = () => [["libraries"]];
export default Toto;

View File

@ -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<HTMLAnchorElement, LinkProps>(function Link(props, ref) {
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props, ref) {
const {
activeClassName = "active",
as,
@ -121,5 +121,3 @@ const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link(props,
/>
);
});
export default Link;

70
front/src/utils/query.ts Normal file
View File

@ -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 <https://www.gnu.org/licenses/>.
*/
import { ComponentType } from "react";
import { dehydrate, QueryClient, QueryFunctionContext, useQuery } from "react-query";
const isServer = () => typeof window === "undefined"
const queryFn = async <T>(context: QueryFunctionContext): Promise<T> => {
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<Props = {}> = ComponentType<Props> & {
getFetchUrls?: (route: { [key: string]: string }) => [[string]];
};
export const useFetch = <Data>(...params: [string]) => {
return useQuery<Data, any>(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);
};

View File

@ -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"

View File

@ -50,7 +50,7 @@ namespace Kyoo.WebApp
public Dictionary<string, Type> Configuration => new();
/// <inheritdoc />
public bool Enabled => Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"));
public bool Enabled => false; // Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"));
/// <summary>
/// Create a new <see cref="WebAppModule"/>.