mirror of
https://github.com/MODSetter/SurfSense.git
synced 2025-09-02 10:39:13 +00:00
176 lines
No EOL
7.8 KiB
Text
176 lines
No EOL
7.8 KiB
Text
---
|
|
title: Next.js config
|
|
"og:title": "Next.js config and setup"
|
|
"description": "Next.js config and setup"
|
|
---
|
|
|
|
## Introduction
|
|
|
|
The frontend uses the latest version of Next.js and TypeScript; it is configured using the latest [app router](https://nextjs.org/docs/app).
|
|
|
|
You can run the **frontend only** by running the `pnpm run dev` command from a terminal within the `web` directory. Alternatively, you can run the entire application by running `pnpm run dev` from the **root directory**.
|
|
|
|
## App structure
|
|
|
|
The app root directory is structured as follows:
|
|
|
|
```
|
|
web
|
|
├── app
|
|
├── components
|
|
├── lib
|
|
├── public
|
|
├── .env
|
|
├── .env.example
|
|
├── .eslintrc.js
|
|
├── components.json
|
|
├── next.config.js
|
|
├── package.json
|
|
├── postcss.config.js
|
|
├── README.md
|
|
├── tailwind.config.js
|
|
├── tsconfig.json
|
|
└── yarn.lock
|
|
```
|
|
|
|
#### App
|
|
|
|
| Item | Description |
|
|
| ----------- | ---------------------------------------------------------------------------------------------------- |
|
|
| globals.css | Tailwind global config. Uses a generated theme from [ShadCN UI themes](https://ui.shadcn.com/themes) |
|
|
| layout.tsx | App layout |
|
|
| page.tsx | Landing page |
|
|
|
|
#### Components
|
|
|
|
| Item | Description |
|
|
| ------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
| layouts | The dashboard layout is stored which wraps the application `{children}` in `root/app/layout.tsx` |
|
|
| theme | The `ThemeProvider` component(s) that wrap the application. |
|
|
| ui | Where `ShadCN` components are stored upon being generated. Configured by the `components.json` located in the `frontend root` |
|
|
| \*.tsx | Components used within the application |
|
|
|
|
#### Lib
|
|
| Item | Description |
|
|
| ----------- | ---------------------------------------------------------------------------------------------------------------- |
|
|
| api | The output generated by the `openapi` npm package. Configured in the `package.json` task named `generate-client` |
|
|
| config | Stores site config. Currently contains the setup for sidebar navigation |
|
|
| twConfig.ts | Tailwind colour config exported to an accessible Object. Used for assigning theme-aware colours in charts |
|
|
| utils.ts | ShadCN utils |
|
|
|
|
|
|
|
|
## TypeScript from FastAPI
|
|
As FastAPI is based on the OpenAPI specification, you get automatic compatibility with many tools, including the automatic API docs (provided by Swagger UI).
|
|
|
|
One particular advantage that is not necessarily obvious is that you can generate clients (sometimes called SDKs ) for your API, for many different programming languages.
|
|
|
|
<Note>For a more detailed explanation, see the [official FastAPI documentation](https://fastapi.tiangolo.com/advanced/generate-clients/#generate-a-typescript-client-with-the-preprocessed-openapi)</Note>
|
|
|
|
## Why generate TypeScript?
|
|
Generating a TypeScript client for your FastAPI backend is a great way to ensure that your frontend and backend are always in sync. It is also a way to provide type hinting while writing your frontend code without needing a permanent reference to the API, or re-creating the schema using something like Zod.
|
|
|
|
<Frame caption="Type hinting from the generated API client"><img src="/_images/type-hinting.png" /></Frame>
|
|
|
|
### How to generate TypeScript
|
|
<Steps>
|
|
<Step title="Configure and run generate-client task">
|
|
There are two generate-client tasks configured in the `package.json`:
|
|
```JSON
|
|
"scripts": {
|
|
...
|
|
"generate-client": "openapi --input https://next-fast-turbo.vercel.app/openapi.json --output ./lib/api/client --client axios --useOptions --useUnionTypes",
|
|
"generate-client:dev": "openapi --input http://127.0.0.0:8000/openapi.json --output ./lib/api/client --client axios --useOptions --useUnionTypes"
|
|
...
|
|
},
|
|
```
|
|
The `generate-client` task is set to run off the production OpenAPI schema.\
|
|
\
|
|
The `generate-client:dev` task is set to use the localhost OpenAPI schema. This is useful for development, as it will use the latest schema from the backend.
|
|
|
|
Ensure your production API URL is configured, or that your local API URL is correct, and then run the relevant task.
|
|
</Step>
|
|
|
|
<Step title="Update your root layout">
|
|
|
|
A key file to be aware of is the `OpenAPI.ts` which is generated in the `lib/api/client/core` directory. This file has the main configuration for the API connection as below:
|
|
|
|
```tsx lib/api/client/core/OpenAPI.ts
|
|
export const OpenAPI: OpenAPIConfig = {
|
|
BASE: "http://127.0.0.0:8000",
|
|
VERSION: "0.1.0",
|
|
WITH_CREDENTIALS: false,
|
|
CREDENTIALS: "include",
|
|
TOKEN: undefined,
|
|
USERNAME: undefined,
|
|
PASSWORD: undefined,
|
|
HEADERS: undefined,
|
|
ENCODE_PATH: undefined,
|
|
};
|
|
```
|
|
|
|
The problem with this is that we would want to differentiate between which API is being used. When the TypeScript is generated, the given OpenAPI URL is used as the base URL for the API.
|
|
This is not ideal for production, as you would want to use the production API URL, and vice versa in development.
|
|
|
|
You can override this by adding the following to your root `layout.tsx` file:
|
|
|
|
```tsx layout.tsx
|
|
import { OpenAPI } from "@/lib/api/client";
|
|
|
|
if (process.env.NODE_ENV === "production") {
|
|
OpenAPI.BASE = "https://next-fast-turbo.vercel.app"
|
|
}
|
|
|
|
```
|
|
|
|
|
|
</Step>
|
|
</Steps>
|
|
|
|
## Using the generated API
|
|
Once you have generated your TypeScript interface to your API, you can use it in your frontend code.
|
|
|
|
In its simplest form, you can import the generated API and use it as below:
|
|
|
|
```tsx
|
|
import { UsersService } from "@/lib/api/client";
|
|
|
|
const response = await UsersService.usersSearchUsers({
|
|
keyword: "keyword",
|
|
searchOn: "searchOn",
|
|
maxResults: "maxResults",
|
|
});
|
|
```
|
|
|
|
You can see this code being used in the `components/search-users.tsx` file, as part of the form's onSubmit function:
|
|
|
|
```tsx
|
|
const onSubmit = async (data: z.infer<typeof FormSchema>) => {
|
|
try {
|
|
const maxResults = data.searchResults ? parseInt(data.searchResults) : 10;
|
|
const response = await UsersService.usersSearchUsers({
|
|
keyword: data.keyword,
|
|
searchOn: data.searchOn,
|
|
maxResults: maxResults,
|
|
});
|
|
setSearchResults(response);
|
|
setError(null);
|
|
} catch (error) {
|
|
setSearchResults({ results: [] });
|
|
setError(error);
|
|
}
|
|
};
|
|
```
|
|
This code also imports the `UserSearchResults` type which is used to set the state of the search results:
|
|
```tsx
|
|
import { UsersService, UserSearchResults } from "@/lib/api/client";
|
|
|
|
const [searchResults, setSearchResults] = React.useState<UserSearchResults>({
|
|
results: [],
|
|
});
|
|
```
|
|
|
|
|
|
## Important considerations
|
|
- If you make changes to your API, you will need to re-generate the TypeScript interface.
|
|
- Re-generating this interface will overwrite the existing files. If you want to modify anything (e.g. `api/client/core/OpenAPI.ts`) and have it persist, do this outside of the generated files. You can see this in action in the `root/app/layout.tsx` file. |