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 Method Server-side rendering with Javascript disabled? #270

Closed
sgup opened this issue Apr 3, 2024 · 3 comments
Closed

SSR Method Server-side rendering with Javascript disabled? #270

sgup opened this issue Apr 3, 2024 · 3 comments

Comments

@sgup
Copy link

sgup commented Apr 3, 2024

Package Versions:
next: 14.1.0
@apollo/client: 3.9.10
@apollo/experimental-nextjs-app-support: 0.9.1

Hi,

I'm using Nextjs with the App router, and have followed the instructions for incorporating the SSR method from this library. I'm also using it with the useSuspenseQuery hook. Is it possible to have the page render right away, even with JS disabled? As soon as I introduce this hook, all I see is the loading.ts content, even on reloads where it seems to have cached the content server-side.

In my testing it works perfect fine when using the RSC method and passing in the data, so the client components can render fine on the server. Id just like to be able to use SSR/useSuspenseQuery to have proper hydration/client-side cache-and-network to have the latest data.

Here's my code:

// apollo/ApolloWrapper.tsx
'use client';
declare module '@apollo/client' {
  export interface DefaultContext {
    token?: string;
  }
}

import { ApolloLink, HttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
import {
  ApolloNextAppProvider,
  NextSSRInMemoryCache,
  NextSSRApolloClient,
  SSRMultipartLink,
} from '@apollo/experimental-nextjs-app-support/ssr';
import typePolicies from './typePolicies';

const uri = `${process.env.NEXT_PUBLIC_GRAPHQL_URL}/graphql`;

// have a function to create a client for you
function makeClient() {
  const authLink = setContext(async (_, { headers, token }) => {
    return {
      headers: {
        ...headers,
        ...(token ? { authorization: `Bearer ${token}` } : {}),
      },
    };
  });

  const httpLink = new HttpLink({
    // this needs to be an absolute url, as relative urls cannot be used in SSR
    uri,
    // you can disable result caching here if you want to
    // (this does not work if you are rendering your page with `export const dynamic = "force-static"`)
    // fetchOptions: { cache: 'no-store' },
  });

  return new NextSSRApolloClient({
    cache: new NextSSRInMemoryCache({
      typePolicies,
    }),
    link:
      typeof window === 'undefined'
        ? ApolloLink.from([
            new SSRMultipartLink({
              stripDefer: true,
            }),
            authLink.concat(httpLink),
          ])
        : authLink.concat(httpLink),
  });
}

// you need to create a component to wrap your app in
export function ApolloWrapper({ children }: React.PropsWithChildren) {
  return (
    <ApolloNextAppProvider makeClient={makeClient}>
      {children}
    </ApolloNextAppProvider>
  );
}
// app/layout.tsx
export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body className={classNames(subFont.className, 'bg-white')}>
        <ApolloWrapper>
          <AppProviders>
            <HeaderWrapper>{children}</HeaderWrapper>
          </AppProviders>
        </ApolloWrapper>
      </body>
    </html>
  );
}
// app/content/[id]/page.tsx
export default async function Page({ params }: Props) {
  const id = params.id
  return <ContentPage id={id} />;
}
// app/content/[id]/loading.tsx
export default async function Loading() {
  return <div>Loading...</div>
}
export default function ContentPage({
  id,
}: {
  id: number;
}) {
  const { data } = useSuspenseQuery(GetContentDocument, {
    variables: {
      id,
    },
    fetchPolicy: 'cache-and-network',
  });

  return <div>{data?.content?.title}</div>
}
@phryneas
Copy link
Member

phryneas commented Apr 3, 2024

It would work if your browser were a search engine, because in that case, Next.js renders the whole page on the server and flushes it when it is finished - but in the case of normal browsers, Next.js uses React's "out of order" streaming and that requires JS to be enabled.

Your page will still load with the .js files 100% blocked, but there is a little bit of inline JS required to "stitch it together" correctly, because it it streaming over parts of the page as they finish rendering on the server, not in the order they actually appear in the DOM.

@sgup
Copy link
Author

sgup commented Apr 3, 2024

It would work if your browser were a search engine, because in that case, Next.js renders the whole page on the server and flushes it when it is finished - but in the case of normal browsers, Next.js uses React's "out of order" streaming and that requires JS to be enabled.

Ok, good to know! Search engines/SEO is my main concern, so it seems like the next/vercel magic will do that with this lib. Thanks for all your expertise and great work on this library!

@sgup sgup closed this as completed Apr 3, 2024
Copy link
Contributor

github-actions bot commented Apr 3, 2024

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