React 18 Suspense not working on Netlify Hydrogen builds?

Hi there.

We are testing the implementation of Shopify Hydrogen on Netlify: https://hydrogen-horando-test.netlify.app/stream

What we expected was a barrier-free running instance of SSR React with Suspense functionality. While testing locally, our Suspense components were running like expected.

But deployed on Netlify we don’t see any fallback components running while the Suspense component gets streamed from the server.

We have made screenrecordings, to show what we expect and what Netlify in the end delivers. In the Suspense Netlify video you can clearly see, that it waits until all components are loaded, which is not how Suspense should work:

Suspense localhost: Loom | Free Screen & Video Recording Software | Loom

Suspense Netlify: Loom | Free Screen & Video Recording Software | Loom

Now here comes the key question: are Netlify edge functions not supporting SSR streams? The docs state yes (Hydrogen on Netlify | Netlify Docs) but the behavior is differently?!

In case you ask…here is the code:

stream.server.jsx

import { Suspense } from 'react';
import { fetchSync, useQuery } from '@shopify/hydrogen';
import { TestSuspenseComponent } from '~/components/TestSuspenseComponent';
import { TestSuspenseClientComponent } from '~/components/TestSuspenseClientComponent.client';

export default function Stream() {
  return (
    <>
      <ul className='list-disc m-12'>
        <TestSuspenseClientComponent />
        <TestSuspenseComponent />
        {/* Suspense in a Server component with fetchSync */}
        <Suspense fallback={<LoadingFallback />}>
          <SuspenseFetchSyncContent />
        </Suspense>
        {/* Suspense in a Server component with useQuery */}
        <Suspense fallback={<LoadingFallback />}>
          <SuspenseUseQueryContent />
        </Suspense>
      </ul>
    </>
  );
}

function LoadingFallback() {
  return <li>Loading...</li>;
}

function SuspenseFetchSyncContent() {

  const response = fetchSync(
    'https://deelay.me/7000/https://jsonplaceholder.typicode.com/todos/1',
    {
      preload: true
    }
  );
  let result;
  if (response.ok) {
    result = response.json();
  } else {
    console.error(`Unable to load`);
  }
  return <li>{result.title} (Server component delay 7000ms)</li>;

}

function SuspenseUseQueryContent() {
  const { data } = useQuery(
    'test-usequery',
    async () => {
      const response = await fetch(
        'https://deelay.me/9000/https://jsonplaceholder.typicode.com/todos/2',
        {
          headers: {
            accept: 'application/json',
          },
        }
      );
      return await response.json();
    },
    {
      preload: true
    }
  );
  return <li>{data.title} (Server component delay 9000ms)</li>;
}

TestSuspenseClientComponent.client.jsx

import { Suspense } from 'react';
import { fetchSync } from '@shopify/hydrogen';

export const TestSuspenseClientComponent = () => {

  return (
    <>
      <Suspense fallback={<LoadingFallback />}>
        <SuspenseFetchSyncContent />
      </Suspense>
    </>
  );

}

function LoadingFallback() {
  return <li>Loading...</li>;
}

function SuspenseFetchSyncContent() {

  const response = fetchSync(
    'https://deelay.me/3000/https://jsonplaceholder.typicode.com/todos/3'
  );
  let result;
  if (response.ok) {
    result = response.json();
  } else {
    console.error(`Unable to load`);
  }
  return <li>{result.title} (Client component delay 3000ms)</li>;

}

TestSuspenseComponent.jsx

import { Suspense } from 'react';
import { fetchSync } from '@shopify/hydrogen';

export const TestSuspenseComponent = () => {

  return (
    <>
      <Suspense fallback={<LoadingFallback />}>
        <SuspenseFetchSyncContent />
      </Suspense>
    </>
  );

}

function LoadingFallback() {
  return <li>Loading...</li>;
}

function SuspenseFetchSyncContent() {

  const response = fetchSync(
    'https://deelay.me/5000/https://jsonplaceholder.typicode.com/todos/3'
  );
  let result;
  if (response.ok) {
    result = response.json();
  } else {
    console.error(`Unable to load`);
  }
  return <li>{result.title} (Hybrid component delay 5000ms)</li>;

}

Hey @patrick.schneider1,

Do you have a site deployed on Netlify that we can check?

Hi @hrishikesh

of course – check first line from my post :slight_smile:

We are testing the implementation of Shopify Hydrogen on Netlify: https://hydrogen-horando-test.netlify.app/stream

@hrishikesh Sorry my fault, remove the /stream from the url, this is the test page: https://hydrogen-horando-test.netlify.app/

As far as I can tell from reading our bug reports, I believe that we shipped a fix for this earlier today. I may be wrong, but it is a bit after hours to ping the team now so - could you let us know if things are working better now?

1 Like

@fool Thanks for your reply. Nice to finally talk with you, you are doing great work for the community here! So I tested our test instance https://hydrogen-horando-test.netlify.app/ and there it works again! Glad to see, that we can once again rely on Suspense. Wohoo!

1 Like