Client Config
You can configure the client using the client
field inside the app
declaration:
- JavaScript
- TypeScript
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.jsx",
setupFn: import mySetupFunction from "@client/myClientSetupCode.js"
}
}
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.tsx",
setupFn: import mySetupFunction from "@client/myClientSetupCode.ts"
}
}
Root Component
Wasp gives you the option to define a "wrapper" component for your React app.
It can be used for a variety of purposes, but the most common ones are:
- Defining a common layout for your application.
- Setting up various providers that your application needs.
Defining a Common Layout
Let's define a common layout for your application:
- JavaScript
- TypeScript
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.jsx",
}
}
export default function Root({ children }) {
return (
<div>
<header>
<h1>My App</h1>
</header>
{children}
<footer>
<p>My App footer</p>
</footer>
</div>
)
}
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.tsx",
}
}
export default function Root({ children }: { children: React.ReactNode }) {
return (
<div>
<header>
<h1>My App</h1>
</header>
{children}
<footer>
<p>My App footer</p>
</footer>
</div>
)
}
Setting up a Provider
This is how to set up various providers that your application needs:
- JavaScript
- TypeScript
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.jsx",
}
}
import store from './store'
import { Provider } from 'react-redux'
export default function Root({ children }) {
return <Provider store={store}>{children}</Provider>
}
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.tsx",
}
}
import store from './store'
import { Provider } from 'react-redux'
export default function Root({ children }: { children: React.ReactNode }) {
return <Provider store={store}>{children}</Provider>
}
As long as you render the children, you can do whatever you want in your root component.
Read more about the root component in the API Reference.
Setup Function
setupFn
declares a function that Wasp executes on the client before everything else.
Running Some Code
We can run any code we want in the setup function.
For example, here's a setup function that logs a message every hour:
- JavaScript
- TypeScript
export default async function mySetupFunction() {
let count = 1
setInterval(
() => console.log(`You have been online for ${count++} hours.`),
1000 * 60 * 60
)
}
export default async function mySetupFunction(): Promise<void> {
let count = 1
setInterval(
() => console.log(`You have been online for ${count++} hours.`),
1000 * 60 * 60
)
}
Overriding Default Behaviour for Queries
You can change the options for a single Query using the options
object, as described here.
Wasp's useQuery
hook uses react-query
's useQuery
hook under the hood. Since react-query
comes configured with aggressive but sane default options, you most likely won't have to change those defaults for all Queries.
If you do need to change the global defaults, you can do so inside the client setup function.
Wasp exposes a configureQueryClient
hook that lets you configure react-query's QueryClient
object:
- JavaScript
- TypeScript
import { configureQueryClient } from '@wasp/queryClient'
export default async function mySetupFunction() {
// ... some setup
configureQueryClient({
defaultOptions: {
queries: {
staleTime: Infinity,
},
},
})
// ... some more setup
}
import { configureQueryClient } from '@wasp/queryClient'
export default async function mySetupFunction(): Promise<void> {
// ... some setup
configureQueryClient({
defaultOptions: {
queries: {
staleTime: Infinity,
},
},
})
// ... some more setup
}
Make sure to pass in an object expected by the QueryClient
's constructor, as
explained in
react-query's docs.
Read more about the setup function in the API Reference.
Base Directory
If you need to serve the client from a subdirectory, you can use the baseDir
option:
app MyApp {
title: "My app",
// ...
client: {
baseDir: "/my-app",
}
}
This means that if you serve your app from https://example.com/my-app
, the
router will work correctly, and all the assets will be served from
https://example.com/my-app
.
If you set the baseDir
option, make sure that the WASP_WEB_CLIENT_URL
env variable also includes that base directory.
For example, if you are serving your app from https://example.com/my-app
, the WASP_WEB_CLIENT_URL
should be also set to https://example.com/my-app
, and not just https://example.com
.
API Reference
- JavaScript
- TypeScript
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.jsx",
setupFn: import mySetupFunction from "@client/myClientSetupCode.js"
}
}
app MyApp {
title: "My app",
// ...
client: {
rootComponent: import Root from "@client/Root.tsx",
setupFn: import mySetupFunction from "@client/myClientSetupCode.ts",
baseDir: "/my-app",
}
}
Client has the following options:
rootComponent: ClientImport
rootComponent
defines the root component of your client application. It is expected to be a React component, and Wasp will use it to wrap your entire app. It must render its children, which are the actual pages of your application.Here's an example of a root component that both sets up a provider and renders a custom layout:
- JavaScript
- TypeScript
src/client/Root.jsximport store from './store'
import { Provider } from 'react-redux'
export default function Root({ children }) {
return (
<Provider store={store}>
<Layout>{children}</Layout>
</Provider>
)
}
function Layout({ children }) {
return (
<div>
<header>
<h1>My App</h1>
</header>
{children}
<footer>
<p>My App footer</p>
</footer>
</div>
)
}src/client/Root.tsximport store from './store'
import { Provider } from 'react-redux'
export default function Root({ children }: { children: React.ReactNode }) {
return (
<Provider store={store}>
<Layout>{children}</Layout>
</Provider>
)
}
function Layout({ children }: { children: React.ReactNode }) {
return (
<div>
<header>
<h1>My App</h1>
</header>
{children}
<footer>
<p>My App footer</p>
</footer>
</div>
)
}setupFn: ClientImport
You can use this function to perform any custom setup (e.g., setting up client-side periodic jobs).
- JavaScript
- TypeScript
src/client/myClientSetupCode.jsexport default async function mySetupFunction() {
// Run some code
}src/client/myClientSetupCode.tsexport default async function mySetupFunction(): Promise<void> {
// Run some code
}baseDir: String
If you need to serve the client from a subdirectory, you can use the
baseDir
option.If you set
baseDir
to/my-app
for example, that will make Wasp set thebasename
prop of theRouter
to/my-app
. It will also set thebase
option of the Vite config to/my-app
.This means that if you serve your app from
https://example.com/my-app
, the router will work correctly, and all the assets will be served fromhttps://example.com/my-app
.Setting the correct env variableIf you set the
baseDir
option, make sure that theWASP_WEB_CLIENT_URL
env variable also includes that base directory.For example, if you are serving your app from
https://example.com/my-app
, theWASP_WEB_CLIENT_URL
should be also set tohttps://example.com/my-app
, and not justhttps://example.com
.