Open gregbrowndev opened 1 month ago
Hey,
I wouldn't say this is up to us specifically, the issue here are the limitations being quite... hard to work around.
What would circumvent your issue here is not importing from an urql package that depends on React so your server-provider becomes:
import 'server-only'
import {executeExchange} from "@urql/exchange-execute";
import {type Client, type SSRExchange, type Exchange} from "@urql/core";
import {cacheExchange, createClient, ssrExchange} from "@urql/core";
typeof window !== "undefined"
is also not reliable here as this could point at both a streamed as well as an RSC rendering. As you note server-only
forces you into the server-component world so if your intention is to just leverage the execute-exchange
for streamed rendering that is entirely possible.
Describe the bug
Hi,
I'm trying to use the execute exchange in a NextJS project. I've struggled with this over the last week (and posted a Q&A here with what I thought was a solution), but now I think this is a situation not fully considered by URQL.
The problem is I want to initialise the URQL execute exchange with my executable schema in a module marked
"server-only"
to ensure this code is not bundled into the client bundle. Note: the"server-only"
directive comes from the packageyarn add server-only
.The client factory is defined in
src/lib/server.ts
:Note: the
createURQLClientForServer
may or may not need to beasync
, but it was from earlier attempts to solve this issue using the commented out dynamic import which returns a Promise.There is also a corresponding factory function to create the URQL client in the browser environment, in
src/lib/client.ts
:So the problem is how to use these then to initialise the
UrqlProvider
in the layout.The fact
createURQLClientForServer
is marked server-only and is async leads me to think I should create a server-component to wrap the provider. So insrc/contexts/graphql/provider-server.ts
, I have:Using an
async
server component allowscreateURQLClientForServer
to be awaited and avoid conditional rendering, which ultimately makes SSR pointless unless you use streaming SSR on all of your pages (since the SSR would just show a loading state on all of your pages).There's an analogous provider in
src/contexts/graphql/provider-client.ts
Then to put it all together, we need to conditionally render either the server or client provider. This is done in
src/contexts/graphql/provider.ts
:Unfortunately, this throws a compilation error:
Call stack
``` Call Stack eval ../../node_modules/urql/dist/urql.es.js (11:9) (rsc)/../../node_modules/urql/dist/urql.es.js /Users/greg/Development/todo-app/apps/web-ui/.next/server/vendor-chunks/urql.js (30:1) Next.js eval /../../node_modules/@urql/next/dist/urql-next.mjs (rsc)/../../node_modules/@urql/next/dist/urql-next.mjs /Users/greg/Development/todo-app/apps/web-ui/.next/server/vendor-chunks/@urql.js (80:1) Next.js eval /./src/contexts/graphql/provider-server.tsx (rsc)/./src/contexts/graphql/provider-server.tsx /Users/greg/Development/todo-app/apps/web-ui/.next/server/_rsc_node_modules_whatwg-node_fetch_dist_sync_recursive-_rsc_src_contexts_graphql_provider-se-50093c.js (49:1) Next.js Function.__webpack_require__ /Users/greg/Development/todo-app/apps/web-ui/.next/server/webpack-runtime.js (33:43) ```
Note: this error goes away if you mark
src/contexts/graphql/provider.ts
as "use client", but then you are forced to remove the "server-only" fromsrc/lib/server.ts
. With this the application functions as expected, SSR is performed with the execute exchange allowing GraphQL queries in my pages to be resolved in-memory, while CSR works via the fetchExchange. However, I don't think this should be relied upon.I've tried several implementations of
GraphqlProvider
, but they all have the same problems, e.g. using a function to get the provider rather than wrapping it with a new component:So, it seems that supporting "server-only" code is very difficult to achieve for reasons in both NextJS and the execute exchange. I'm not sure if this situation has been fully considered in the NextJS integration.
Reproduction
https://github.com/gregbrowndev/todo-app
Urql version
urql 4.0.7
Validations