How to create a full-stack NextJS 14 app with URQL's executeExchange #3585
-
ContextHi, Just for fun/learning, I'm building a full-stack, monolithic NextJS app using GraphQL-Yoga and URQL. The Yoga server can be embedded into a NextJS API, which allows for client-side rendering with URQL configured with the To perform server-side rendering and ensure all GraphQl requests are handled in-memory, we can replace the The project source can be found here: https://github.com/gregbrowndev/todo-app/ ProblemThe problem I'm running into, for several reasons below, is that creating this exchange requires The file below is in my NextJS project, "use server"
import {executeExchange} from "@urql/exchange-execute";
import {createYoga} from "graphql-yoga";
import { type Context} from "@repo/server/graphql";
import { type Exchange} from "urql";
// Note: executable schema imported from @repo/server
/** Create a local executor
* Returns a URQL exchange for the GraphQL client to use when
* server-side rendering. This allows the NextJS server to resolve
* graphql queries while rendering without making additional network
* requests.
*/
export async function createLocalExecutor(): Promise<Exchange> {
const { schema } = await import("@repo/server/graphql");
return executeExchange({
schema,
context: () => makeContext()
})
}
/** Create a GraphQL Yoga server
* Returns a server that can be embedded into a NextJS route, so it
* can serve graphql requests to the client when client-side rendering.
*/
export async function createHttpExecutor(): Promise<ReturnType<typeof createYoga>> {
const { schema } = await import("@repo/server/graphql");
return createYoga<any, Context>({
schema,
graphqlEndpoint: "/api/graphql",
fetchAPI: { Response },
context: () => makeContext()
})
}
async function makeContext(): Promise<Context> {
// Load environment variables, create DB connection/session, etc.
return {
timeNow: new Date()
};
} From above, you can see several reasons why the exchange becomes
Even if there is a smart solution to solve the bundling problem, I think creating the context for each request will in general require Observation: the Additional commentsSo I hope you can see my issue. My current attempt at solving this is to create a separate Layout/Provider for each environment. We eliminate the conditional rendering (at least the loading state), since the Client for the server environment can be initialised in an The problem now seems to be NextJS/URQL is not happy at all that the content does not "match" between the SSR and CSR.
|
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
So I found the solution! I didn't notice the app had logged out an error message on the server because it had been lost within all the output caused by React going into an infinite render loop. However, this was the error:
Removing the "use server" at the top of So, I was on the right lines by making two Layout objects to initialise the URQL client. The key one is that the server component can be marked |
Beta Was this translation helpful? Give feedback.
So I found the solution!
I didn't notice the app had logged out an error message on the server because it had been lost within all the output caused by React going into an infinite render loop. However, this was the error:
Removing the "use server" at the top of
src/lib/server.ts
was enough to fix the issue.So, I was on the right lines by making two Layout objects to initialise the URQL client. The key one is that…