Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does NextJS SSR work with Apollo Client? When checking with 'view page source' on page first load I don't see my HTML

Edit: is this not working because I'm not calling getInitialProps? NextJS documentation (https://nextjs.org/docs/basic-features/data-fetching#server-side-rendering) says that if you don't then the page is statically rendered at build time. So I should put my useQuery inside getInitialProps?

I'm testing out an Apollo Client front end that connects through GraphQL to a KeystoneJS CMS backend. One method of testing whether SSR is working is, as I understand it, to load a page in a browser, check the source and see if the HTML is in there. It's not working for me.

The page source is as follows (it's ugly, I'm just testing out that connections and SSR work):

import React from 'react';
import Head from 'next/head';
import {useQuery} from '@apollo/react-hooks';
import gql from 'graphql-tag';

const ARTICLES_QUERY = gql`
  query {

   allArticles {
      title
      text
  }
  }
`;

const Home = () => {
    // Create a query hook
    const {data, loading, error} = useQuery(ARTICLES_QUERY);
  console.log(data)
    if (loading) {
        return <p>Loading...</p>;
    }

    if (error) {
        return <p>Error: {JSON.stringify(error)}</p>;
    }
    return (
        <div>
            <Head>
                <title>Home</title>
                <link rel="icon" href="/favicon.ico"/>
            </Head>
            <p>some paragraph text</p>
            <div>And something in a div</div>
            <ul>
                {data?.allArticles?.map(article => {
                    return <li key={`article__${article.title}`}>{article.title}</li>;
                })}
            </ul>
        </div>
    );
};

export default Home;

The page renders as

enter image description here

and the page source for that page is

<!DOCTYPE html><html><head><style data-next-hide-fouc="true">body{display:none}</style><noscript data-next-hide-fouc="true"><style>body{display:block}</style></noscript><meta charSet="utf-8"/><meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/development/pages/index.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/development/pages/_app.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/runtime/webpack.js?ts=1582296618319" as="script"/><link rel="preload" href="/_next/static/runtime/main.js?ts=1582296618319" as="script"/><noscript id="__next_css__DO_NOT_USE__"></noscript></head><body><div id="__next"><p>Loading...</p></div><script src="/_next/static/development/dll/dll_d6a88dbe3071bd165157.js?ts=1582296618319"></script><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{},"apolloState":{},"apollo":null},"page":"/","query":{},"buildId":"development","isFallback":false}</script><script nomodule="" src="/_next/static/runtime/polyfills.js?ts=1582296618319"></script><script async="" data-next-page="/" src="/_next/static/development/pages/index.js?ts=1582296618319"></script><script async="" data-next-page="/_app" src="/_next/static/development/pages/_app.js?ts=1582296618319"></script><script src="/_next/static/runtime/webpack.js?ts=1582296618319" async=""></script><script src="/_next/static/runtime/main.js?ts=1582296618319" async=""></script><script src="/_next/static/development/_buildManifest.js?ts=1582296618319" async=""></script></body></html>

Neither my static HTML nor the dynamic content is in there.

I am missing something obvious here? Is it the Apollo Client cache? Is it something I'm missing about how NextJS should work? This is all on first page load -- that is, I know it's client-side rendered when you navigate on client side, but this should come straight from the server, no?

For what it's worth, pages/_app.js is

import React from 'react';
import App from 'next/app';
import { ApolloProvider } from '@apollo/react-hooks';

import withData from '../util/apollo-client';

class MyApp extends App {
    render() {
        const { Component, pageProps, apollo } = this.props;
        return (
            <ApolloProvider client={apollo}>
                <Component {...pageProps} />
            </ApolloProvider>
        );
    }
}

// Wraps all components in the tree with the data provider
export default withData(MyApp)

and /util/apollo-client.jsis

import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import withApollo from 'next-with-apollo';
import { createHttpLink } from 'apollo-link-http';
import fetch from 'isomorphic-unfetch';

// Update the GraphQL endpoint to any instance of GraphQL that you like
const GRAPHQL_URL = 'http://localhost:3000/admin/api';

const link = createHttpLink({
    fetch, // Switches between unfetch & node-fetch for client & server.
    uri: GRAPHQL_URL
});

// Export a HOC from next-with-apollo
// Docs: https://www.npmjs.com/package/next-with-apollo
export default withApollo(
    // You can get headers and ctx (context) from the callback params
    // e.g. ({ headers, ctx, initialState })
    ({ initialState }) =>
        new ApolloClient({
            link: link,
            cache: new InMemoryCache()
                //  rehydrate the cache using the initial data passed from the server:
                .restore(initialState || {})
        })
);
like image 455
Cerulean Avatar asked Feb 21 '20 14:02

Cerulean


1 Answers

I think ApolloClient is missing ssrMode option

Include the option into your withApollo function as follows:

Example:

// Export a HOC from next-with-apollo
// Docs: https://www.npmjs.com/package/next-with-apollo
export default withApollo(
    // You can get headers and ctx (context) from the callback params
    // e.g. ({ headers, ctx, initialState })
    ({ initialState, ctx }) =>
        new ApolloClient({
            ssrMode: Boolean(ctx),
            link: link,
            cache: new InMemoryCache()
                //  rehydrate the cache using the initial data passed from the server:
                .restore(initialState || {})
        })
);
like image 157
ddon-90 Avatar answered Nov 17 '22 01:11

ddon-90