Unable to use server component slices within the Prismic Simulator

Hi there, first of all I'm really glad to be using Prismic for my new project.

I've encountered my first problem at the beginning of the week and wish to share it with the community.

I've got Slices that need data from a third party (an API). When not in the simulator my "server slices" work perfectly fine. But in the simulator it does not work : the slice doesn't load in the simulator (Fun fact : the client slices do not work either in the simulator as soon as I import the server slice).

I've started to investigate and here is what I've found so far :

slice-simulator/page.tsx

'use client'; 
/**
* Client component because the <SliceSimulator /> comp listens
* to event emitted by SliceMachine to udpate the data of the slice
*/   

import { SliceZone } from '@prismicio/react';
import { SliceSimulator } from '@slicemachine/adapter-next/simulator';

import { components } from '@/slices/client-slices';

export default function SliceSimulatorPage() {
 return (
   <SliceSimulator
     sliceZone={(props) => <SliceZone {...props} components={components} />}
   />
 );
}

By design, a client component cannot render server components if they're not passed as children of the said client component.

So now i'm locked.

As a "mitigation solution" i've created a copy of slices/index.ts file called slices/client-slices.ts excluding server components in order to still be able to use the SliceSimulator with my other Slices.

I know I could create API routes providing the data I need for my server components and retrieve it with useEffect in order to keep my slices "client", but that's not something I want to do because it would mean using bad pattern in order to make a dev-tool work, and I'm not found of that.

Aditional information :

package.json

{
  "dependencies": {
    "@prismicio/client": "latest",
    "@prismicio/next": "latest",
    "@prismicio/react": "latest",
    "next": "^14.0.4",
  },
  "devDependencies": {
    "@slicemachine/adapter-next": "latest",
  }
}

Kind regards,
Julien.

3 Likes

Hi @Julien_Rousset and welcome to the Prismic Community,

Allow me to recap to check my understanding of your post.

You're using slice-machine's Slice Simulator with NextJS and the App router. In your slice, you're fetching data asynchronously from a third party API. While in Slice Simulator, you can't see your slice loading.

You point out that the page.tsx file in slice-simulator is a client component.
Thank you also for sharing your dependencies.

I went to one of my projects to test this. I have a slice called Content. It's a richtext field only. I converted it to an async functional component and then used Prismic as my third-party API to fetch from. It appears to work for me in my slice simulator. Here's my code for this:

// all the imports would be up here...

/**
 * Component for "Content" Slices.
 */
const Content = async ({ slice }: ContentProps): Promise<JSX.Element> => {
  const client = createClient()
  const settings = await client.getSingle('settings')
  const title = prismic.asText(settings.data.site_title)
return (
        <Section
          width="lg"
          data-slice-type={slice.slice_type}
          data-slice-variation={slice.variation}
          className="prose mx-auto block w-full dark:prose-invert lg:prose-lg xl:prose-xl 2xl:prose-2xl"
        >
          <p className="text-black">{title}</p>
          <PrismicRichText field={slice.primary.content} />
        </Section>
      )
}
export default Content

Slice-Simulator shows (keep in mind slice simulator doesn't play well with dark themes)

The dependencies:

"dependencies": {
    "@prismicio/client": "latest",
    "@prismicio/next": "latest",
    "@prismicio/react": "latest",
    "@radix-ui/react-dialog": "^1.0.5",
    "@radix-ui/react-slot": "^1.0.2",
    "@react-three/drei": "^9.92.7",
    "@react-three/fiber": "^8.15.12",
    "@tailwindcss/aspect-ratio": "^0.4.2",
    "@types/react-syntax-highlighter": "^15.5.11",
    "@types/three": "^0.160.0",
    "class-variance-authority": "^0.7.0",
    "clsx": "^2.0.0",
    "gsap": "^3.12.4",
    "lucide-react": "^0.303.0",
    "next": "latest",
    "react": "^18",
    "react-dom": "^18",
    "react-syntax-highlighter": "^15.5.0",
    "tailwind-merge": "^2.2.0",
    "tailwindcss-animate": "^1.0.7",
    "three": "^0.160.0"
  },
  "devDependencies": {
    "@slicemachine/adapter-next": "latest",
    "@tailwindcss/typography": "latest",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "concurrently": "latest",
    "eslint": "^8",
    "eslint-config-next": "14.0.4",
    "postcss": "^8",
    "prettier": "latest",
    "prettier-plugin-tailwindcss": "latest",
    "schema-dts": "latest",
    "slice-machine-ui": "latest",
    "tailwindcss": "^3.3.0",
    "typescript": "^5"
  }

Hello @nf_mastroianni,

First of all, thanks for taking the time to give me an answer.

There is a slight possibility that your await client.getSingle('settings') is cached by Next if it's based on the fetch from Next, making it a 0 tick async operation and therefore not messing with the client comp having to render server comp.

I dived into my issue and think there is a problem with rendering server component within the simulator which have access to the package fs. I'll keep digging and keep you updated. In the mean time if you have other suggestions I'll be glad to hear them.

Kind regards.

1 Like

I would also like to see a solution/guidance on this issue. The overwhelming majority of our slices are server components, which by good fortune render in slice simulator until you need to call a server only function like e.g. headers() from next/headers. Then you get an error like such "You're importing a component that needs next/headers. That only works in a Server Component which is not supported in the pages/ directory. Read more: Building Your Application: Rendering | Next.js".
Note: the slice-simulator page is in the app directory and not the pages directory.

1 Like

Hi,

Thanks for all of your comments. We are aware of the problem that impacts also the Live preview of Slices in the new page builder.

Our team plans to look a this issue next week, we'll come back to you with more news on that front after a first investigation.

All the best,

Côme, Devtools Team

1 Like

Hi Team,

The latest release of Slice Machine now supports server components :slight_smile:

You'll need to update your simulator page:

// src/app/slice-simulator/page.tsx

import {
  SliceSimulator,
  SliceSimulatorParams,
  getSlices,
} from "@slicemachine/adapter-next/simulator";
import { SliceZone } from "@prismicio/react";

import { components } from "@/slices";

export default function SliceSimulatorPage({
  searchParams,
}: SliceSimulatorParams) {
  const slices = getSlices(searchParams.state);

  return (
    <SliceSimulator>
      <SliceZone slices={slices} components={components} />
    </SliceSimulator>
  );
}

Happy coding!

1 Like