Skip to content

Commit 8230006

Browse files
committed
improve orval generation and use loader to prefetch
1 parent 59d642b commit 8230006

File tree

9 files changed

+351
-124
lines changed

9 files changed

+351
-124
lines changed

orval.config.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { defineConfig } from "orval";
2+
export default defineConfig({
3+
todos: {
4+
output: {
5+
target: "src/todos-api/client.gen.ts",
6+
client: "react-query",
7+
override: {
8+
mutator: {
9+
path: "src/todos-api/axiosInstance.ts",
10+
name: "fetch"
11+
}
12+
}
13+
},
14+
hooks: {
15+
afterAllFilesWrite: "yarn format"
16+
}
17+
}
18+
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"type": "module",
88
"scripts": {
99
"postinstall": "vite-envs update-types",
10-
"dev": "vite --host",
10+
"dev": "vite",
1111
"build": "tsc -b && vite build",
1212
"lint": "eslint ./src",
1313
"preview": "vite preview",

scripts/generate-todos-api-client.ts

Lines changed: 12 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import * as fs from "fs";
2-
import { join as pathJoin } from "path";
2+
import { join as pathJoin, resolve } from "path";
33
import { assert } from "tsafe/assert";
44
import fetch from "node-fetch";
55
import * as child_process from "child_process";
6-
import type { defineConfig } from "orval";
7-
import type { Param0 } from "tsafe";
86

97
const projectDirPath = process.cwd();
108

@@ -36,41 +34,22 @@ const projectDirPath = process.cwd();
3634
await fetch(`${todosApiUrl}/doc`).then(response => response.text())
3735
);
3836

37+
const originalOrvalConfigPath = pathJoin(projectDirPath, "orval.config.ts");
3938
const orvalConfigFilePath = pathJoin(cacheDirPath, "orval.config.ts");
4039

41-
const todosApiSrcDirPath = pathJoin(projectDirPath, "src", "todos-api");
40+
const configContent = fs
41+
.readFileSync(originalOrvalConfigPath, "utf-8")
42+
.replace(/(path|target):\s*['"]([^'"]+)['"]/g, (_, key, relativePath) => {
43+
const absolutePath = resolve(projectDirPath, relativePath);
44+
return `${key}: '${absolutePath.replace(/\\/g, "\\\\")}'`;
45+
})
46+
.replace(/todos:\s*{/, match => {
47+
return `${match}\n input: '${todosOpenApiJsonFilePath.replace(/\\/g, "\\\\")}',`;
48+
});
4249

43-
const generatedFilePath = pathJoin(todosApiSrcDirPath, "client.gen.ts");
44-
45-
const orvalConfig: Param0<typeof defineConfig> = {
46-
todos: {
47-
input: todosOpenApiJsonFilePath,
48-
output: {
49-
target: generatedFilePath,
50-
override: {
51-
mutator: {
52-
path: pathJoin(todosApiSrcDirPath, "axiosInstance.ts"),
53-
name: "fetch"
54-
}
55-
}
56-
}
57-
}
58-
};
59-
60-
fs.writeFileSync(
61-
orvalConfigFilePath,
62-
Buffer.from(
63-
[
64-
`import { defineConfig } from "orval";`,
65-
`export default defineConfig(${JSON.stringify(orvalConfig)});`
66-
].join("\n"),
67-
"utf8"
68-
)
69-
);
50+
fs.writeFileSync(orvalConfigFilePath, configContent, "utf-8");
7051

7152
run(`npx orval --config ${orvalConfigFilePath}`);
72-
73-
run(`npx prettier --write ${generatedFilePath}`);
7453
})();
7554

7655
function run(command: string) {

src/main.lazy.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import { routeTree } from "./routeTree.gen";
77
import { I18nFetchingSuspense } from "i18n";
88
import { MuiDsfrThemeProvider } from "@codegouvfr/react-dsfr/mui";
99
import { useLang } from "i18n";
10+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
11+
12+
const queryClient = new QueryClient();
13+
14+
const router = createRouter({ routeTree, context: { queryClient }, defaultPreload: "intent" });
1015

11-
const router = createRouter({ routeTree });
1216
// Register the router instance for type safety
1317
declare module "@tanstack/react-router" {
1418
interface Register {
@@ -33,12 +37,14 @@ startReactDsfr({
3337

3438
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
3539
<React.StrictMode>
36-
<MuiDsfrThemeProvider>
37-
<OidcProvider>
38-
<I18nFetchingSuspense>
39-
<RouterProvider router={router} />
40-
</I18nFetchingSuspense>
41-
</OidcProvider>
42-
</MuiDsfrThemeProvider>
40+
<QueryClientProvider client={queryClient}>
41+
<MuiDsfrThemeProvider>
42+
<OidcProvider>
43+
<I18nFetchingSuspense>
44+
<RouterProvider router={router} />
45+
</I18nFetchingSuspense>
46+
</OidcProvider>
47+
</MuiDsfrThemeProvider>
48+
</QueryClientProvider>
4349
</React.StrictMode>
4450
);

src/oidc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ if (!issuerUri) {
1717
console.log("============= VITE_OIDC_ISSUER_URI not set, USING MOCK OIDC =============");
1818
}
1919

20-
export const { OidcProvider, useOidc, getOidc, enforceLogin } = issuerUri
20+
export const { OidcProvider, useOidc, getOidc, enforceLogin, withLoginEnforced } = issuerUri
2121
? createReactOidc({
2222
issuerUri,
2323
clientId,

src/routes/__root.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { createRootRouteWithContext, Outlet } from "@tanstack/react-router";
2+
import { QueryClient } from "@tanstack/react-query";
23
import { Footer } from "components/Footer";
34
import { Header } from "components/Header";
45
import { fr } from "@codegouvfr/react-dsfr";
56
import { AutoLogoutCountdown } from "components/AutoLogoutCountdown";
67
import { tss, GlobalStyles } from "tss";
78

8-
export const Route = createRootRouteWithContext()({
9+
export const Route = createRootRouteWithContext<{
10+
queryClient: QueryClient;
11+
}>()({
912
component: RootComponent,
1013
notFoundComponent: () => <>The route is not defined</>
1114
});

src/routes/todo.tsx

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,40 @@ import { fr } from "@codegouvfr/react-dsfr";
77
import { assert } from "tsafe/assert";
88
import CircularProgress from "@mui/material/CircularProgress";
99
import { declareComponentKeys, useTranslation } from "i18n";
10+
import { getGetTodosQueryOptions } from "todos-api/client.gen";
1011

1112
export const Route = createFileRoute("/todo")({
1213
component: Page,
14+
pendingComponent: PendingTodo,
1315
beforeLoad: async params => {
1416
await enforceLogin(params);
17+
},
18+
loader: async ({ context: { queryClient }, abortController }) => {
19+
queryClient.prefetchQuery(
20+
getGetTodosQueryOptions({ request: { signal: abortController.signal } })
21+
);
1522
}
1623
});
1724

25+
function PendingTodo() {
26+
const { classes } = useStyles();
27+
const { t } = useTranslation("TodoPage");
28+
29+
return (
30+
<div className={classes.circularProgressWrapper}>
31+
<CircularProgress />
32+
<br />
33+
<h5 className={classes.delayedMessage}>{t("waking up container")}</h5>
34+
</div>
35+
);
36+
}
1837
function Page() {
1938
const { todos, createTodo, deleteTodo, updateTodo, isPending } = useTodosApi();
2039

2140
const { classes } = useStyles();
2241

23-
const { t } = useTranslation("TodoPage");
24-
2542
if (todos === undefined) {
26-
return (
27-
<div className={classes.circularProgressWrapper}>
28-
<CircularProgress />
29-
<br />
30-
<h5 className={classes.delayedMessage}>{t("waking up container")}</h5>
31-
</div>
32-
);
43+
return <PendingTodo />;
3344
}
3445

3546
return (
@@ -38,17 +49,17 @@ function Page() {
3849
className={classes.todoApp}
3950
todos={todos}
4051
isPending={isPending}
41-
onAddTodo={createTodo}
42-
onDeleteTodo={deleteTodo}
43-
onUpdateTodoText={(id, text) => updateTodo({ id, text })}
52+
onAddTodo={(text: string) => createTodo({ data: { text } })}
53+
onDeleteTodo={(id: string) => deleteTodo({ id })}
54+
onUpdateTodoText={(id, text) => updateTodo({ id, data: { text } })}
4455
onToggleTodo={id => {
4556
const todo = todos.find(todo => todo.id === id);
4657

4758
assert(todo !== undefined);
4859

4960
updateTodo({
5061
id,
51-
isDone: !todo.isDone
62+
data: { isDone: !todo.isDone }
5263
});
5364
}}
5465
/>

0 commit comments

Comments
 (0)