Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useSuspenseQuery results in a pre-render error on build #441

Closed
sandrosxila opened this issue Feb 22, 2025 · 3 comments
Closed

useSuspenseQuery results in a pre-render error on build #441

sandrosxila opened this issue Feb 22, 2025 · 3 comments

Comments

@sandrosxila
Copy link

sandrosxila commented Feb 22, 2025

Code

// src/apollo-client.ts
import { ApolloLink, concat, HttpLink } from "@apollo/client";
import {
  registerApolloClient,
  ApolloClient,
  InMemoryCache,
} from "@apollo/experimental-nextjs-app-support";
import { cookies } from "next/headers";

export const { getClient, query, PreloadQuery } = registerApolloClient(
  async () => {
    const cookieStore = await cookies();
    const token = cookieStore.get("authToken")?.value;

    const authMiddleware = new ApolloLink((operation, forward) => {
      if (token) {
        operation.setContext({
          headers: {
            Authorization: `Bearer ${token}`,
          },
        });
      }

      return forward(operation);
    });

    const httpLink = new HttpLink({
      uri: process.env.NEXT_PUBLIC_GRAPHQL_API_URL,
    });

    return new ApolloClient({
      cache: new InMemoryCache(),
      link: concat(authMiddleware, httpLink),
    });
  }
);
// src/providers/apollo-provider.tsx
"use client";

import { HttpLink, ApolloLink, concat, split } from "@apollo/client";
import {
  ApolloNextAppProvider,
  ApolloClient,
  InMemoryCache,
} from "@apollo/experimental-nextjs-app-support";
import Cookies from 'js-cookie';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';
import { getMainDefinition } from "@apollo/client/utilities";

// have a function to create a client for you
function makeClient() {
  const httpLink = new HttpLink({
    uri: process.env.NEXT_PUBLIC_GRAPHQL_API_URL,
    fetchOptions: { cache: "no-store" },
  });
  
  const wsLink = new GraphQLWsLink(createClient({
    url: process.env.NEXT_PUBLIC_GRAPHQL_API_URL_WSS,
    connectionParams: () => {
      const token = Cookies.get('authToken');

      return {
        authToken: token
      }
    },
    disablePong: false,
    retryAttempts: 3,
    keepAlive: 60 * 1000,
  }));
  
  // The split function takes three parameters:
  //
  // * A function that's called for each operation to execute
  // * The Link to use for an operation if the function returns a "truthy" value
  // * The Link to use for an operation if the function returns a "falsy" value
  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === 'OperationDefinition' &&
        definition.operation === 'subscription'
      );
    },
    wsLink,
    httpLink,
  );

  const authMiddleware = new ApolloLink((operation, forward) => {
    const token = Cookies.get('authToken');

    operation.setContext({
      headers: {
        Authorization: token ? `Bearer ${token}` : "",
      },
    });

    return forward(operation);
  });

  // use the `ApolloClient` from "@apollo/experimental-nextjs-app-support"
  return new ApolloClient({
    // use the `InMemoryCache` from "@apollo/experimental-nextjs-app-support"
    cache: new InMemoryCache(),
    link: concat(authMiddleware, splitLink),
  });
}

// you need to create a component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
  return (
    <ApolloNextAppProvider makeClient={makeClient}>
      {children}
    </ApolloNextAppProvider>
  );
}
// src/app/layout.tsx

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { ApolloWrapper } from "@/providers/apollo-provider";
import { Navbar } from "@/components/navbar";
import { Toaster } from "react-hot-toast";
import { Suspense } from "react";
import Loading from "./loading";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: "Take Home",
  description: "GraphQL + Next",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body className={`${geistSans.variable} ${geistMono.variable}`}>
        <Toaster position="bottom-right" reverseOrder={false} />
        <Navbar />
        <main className="flex flex-col py-2">
          <ApolloWrapper>
            {children}
          </ApolloWrapper>
        </main>
      </body>
    </html>
  );
}
// src/app/page.tsx

import { PreloadQuery } from "@/apollo-client";
import { GetProductsDocument } from "@/generated/graphql";
import { Products } from "@/components/products";

export default async function Home() {
  return (
    <div className="container flex grow justify-center w-full self-center">
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
        <PreloadQuery query={GetProductsDocument}>
          <Products />
        </PreloadQuery>
      </div>
    </div>
  );
}
// src/components/Products.tsx
"use client";

import React from "react";
import { GetProductsDocument } from "@/generated/graphql";
import { useSuspenseQuery } from "@apollo/client";

export const Products = () => {
  const {} = useSuspenseQuery(GetProductsDocument);

  return <></>;
};

problem

When I run next build I get an error:

Error occurred prerendering page "/". Read more: https://nextjs.org/docs/messages/prerender-error
ApolloError: Query failed upstream.
    at new t (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:40255)
    at /home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:167371
    at i (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:135108)
    at /home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:135023
    at new Promise (<anonymous>)
    at Object.then (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:134990)
    at Object.error (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:3:135118)
    at g (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:191:5580)
    at b (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:191:6081)
    at t.error (/home/sandro/Desktop/projects/shopping-cart-manager/.next/server/chunks/686.js:191:6634)
Export encountered an error on /page: /, exiting the build.
 ⨯ Next.js build worker exited with code: 1 and signal: null
@phryneas
Copy link
Member

This seems to be caused by static prerendering in combination with fetchOptions: { cache: "no-store" } - see #339.

I've opened a PR on the Next.js side, but so far they haven't reacted to it: vercel/next.js#74145

In the meantime, you won't be able to combine these two features.

@sandrosxila
Copy link
Author

sandrosxila commented Feb 23, 2025

Thanks for your fast response, I fixed it ❤️ .

Copy link
Contributor

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants