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

SSR not working properly #335

Open
juanstiza opened this issue Jul 19, 2024 · 7 comments
Open

SSR not working properly #335

juanstiza opened this issue Jul 19, 2024 · 7 comments

Comments

@juanstiza
Copy link

Hi all!

I'm having a strange issue while setting up SSR. I haven't found this problem being described anywhere else. Any help will be appreciated!

What I expect:

Loading the page in the browser without javascript should render the correct content.

What I get:

The page renders only the fallback. If I load the page again without restarting the server, I can see the content.

Dependencies

react: ^18, installed: 18.2.0
@apollo/client: ^3.10.8, installed: 3.10.8
@apollo/experimental-nextjs-app-support: ^0.11.2, installed: 0.11.2
graphql: ^16.9.0, installed: 16.9.0

Setup

Apollo provider

// ApolloPrpovider.tsx
'use client';
import { ApolloLink, HttpLink } from '@apollo/client';
import {
  ApolloClient,
  ApolloNextAppProvider,
  InMemoryCache,
  SSRMultipartLink,
} from '@apollo/experimental-nextjs-app-support';
import React from 'react';

function makeClient() {
  const httpLink = new HttpLink({
    uri: 'https://myapi.com/graphql',
  });

  return new ApolloClient({
    cache: new InMemoryCache(),
    ssrMode: true,
    link:
      typeof window === 'undefined'
        ? ApolloLink.from([
            new SSRMultipartLink({
              stripDefer: true,
            }),
            httpLink,
          ])
        : httpLink,
  });
}

export function ApolloWrapper({ children }: React.PropsWithChildren) {
  return (
    <ApolloNextAppProvider makeClient={makeClient}>
      {children}
    </ApolloNextAppProvider>
  );
}

Page component

// src/app/product/page.tsx
import React from 'react';
import { MyPage } from '@/app/components/ProductPage';

export default function Page({ params }: { params: { slug: string } }) {
  return <ProductPage urlSlug={params.slug} />;
}

Content component

// src/components/ProductPage.tsx
import React, { Suspense } from 'react';
import Content from '@/app/components/Product';

export const ProductPage: React.FC<{
  urlSlug: string;
}> = ({ urlSlug }) => {
  return (
    <Suspense fallback={'Loading...'}>
      <Product urlSlug={urlSlug} />
    </Suspense>
  );
};

Product component, it should render the product's title.

// src/component/Product.tsx
'use client';
import { useSuspenseQuery } from '@apollo/client';
import query from '@/feature/product.query';

export const dynamic = 'force-dynamic';

export default function Product({
  urlSlug,
}: {
  urlSlug: string;
}) {
  const { data, error } = useSuspenseQuery(query, {
    variables: {
      slug: urlSlug,
    },
  });
  const product = data.product;

  return product.title;
}
@juanstiza
Copy link
Author

Here I provide a repro. repo: https://github.com/juanstiza/apollo-client-nextjs-repro.

@juanstiza juanstiza reopened this Jul 19, 2024
Copy link

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.

@alessbell
Copy link
Member

Hi @juanstiza 👋

Your question brings up an interesting fact about React streaming SSR: it requires JavaScript on the client in order to work. With progressive hydration, after the initial HTML of your application is rendered and sent to the browser, React generates the HTML for suspending components as they receive data and sends it to the same stream along with a script tag so it can be rendered in place of the fallback that was in the initial HTML payload.

If you remove Apollo Client from your example and replace it with a different data fetching hook that does some asynchronous work you should see the same thing. I'll leave this issue open for now, let me know if you have any other questions :)

@juanstiza
Copy link
Author

If you remove Apollo Client from your example and replace it with a different data fetching hook that does some asynchronous work you should see the same thing. I'll leave this issue open for now, let me know if you have any other questions :)

@alessbell Indeed, we used to do it like this but using Apollo, without the new hooks and streaming.

I guess we'll keep it like that until another solution arises. Thanks for the insight!

@phryneas
Copy link
Member

One thing to add maybe: if Next.js detects a search engine crawler, they will not show suspense fallbacks and start out-of-order-streaming, but instead wait until all data has been fetched and then flush the whole page in order, so it will not require JavaScript from the perspective of a web crawler.

The behaviour you are seeing here is reserved for real users with real browsers.

@juanstiza
Copy link
Author

@phryneas This is interesting! is there a way of tricking Next.js to render the page as if I were a crawler?

I'm googling it as I finish typing this :)

@phryneas
Copy link
Member

https://github.com/vercel/next.js//blob/efcec4c1e303848a5293cef6961be8f73fd5160b/packages/next/src/shared/lib/router/utils/is-bot.ts

You'd set a user-agent accordingly.

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

3 participants