Skip to content

plasmicapp/plasmic-nextjs-app-router-experimental

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

An extremely ugly experiment for doing extractPlasmicQueryData() for nextjs appdir.

We normally use react-ssr-prepass to fake-render a React tree to gather data requirements. We can't do so in RSC mode, because all the client components are imported as placeholders, so we cannot fake-render them.

The idea here is to use the dev server's SSR instead! At SSR time (instead of RSC time), we do have access to imported client components. So... we could do pre-rendering there, gather the data needs, and respond with them. At RSC time, we hit the SSR endpoint, and parse out the data needs.

So...

  1. Create a app/plasmic-ssr/[[...catchall]]/page.tsx route, whose purpose is to perform SSR. It looks something like...
import { ExtractPlasmicQueryData } from "@plasmicapp/nextjs-app-router-experimental";

export default async function CatchallPrepass(props: {
  params?: Params;
}) {
  const { params } = props;

  const plasmicPath = params.catchall ? `/${params.catchall.join("/")}` : "/";
  const prefetchedData = await PLASMIC.maybeFetchComponentData(plasmicPath);
  if (!prefetchedData || prefetchedData.entryCompMetas.length === 0) {
    notFound();
  }

  const pageMeta = prefetchedData.entryCompMetas[0];

  return (
    <ExtractPlasmicQueryData>
      <PlasmicClientRootProvider
        prefetchedData={prefetchedData}
        pageParams={pageMeta.params}
      >
        <PlasmicComponent
          component={pageMeta.displayName}
        />
      </PlasmicClientRootProvider>
    </ExtractPlasmicQueryData>
  )
}

<ExtractPlasmicQueryData /> is a new client component from this package, which basically performs extractPlasmicQueryData() on its children, and then renders a <script data-plasmic-prefetch-id/> tag with the json of the extracted data.

  1. From the real app/[...catchall]/page.tsx file, make use of this endpoint to read the extracted data:
import { fetchExtractedQueryData } from "@plasmicapp/nextjs-app-router-experimental";

export default async function Catchall(props: {
  params?: Params;
}) {
  const { params } = props;

  const plasmicPath = params.catchall ? `/${params.catchall.join("/")}` : "/";
  const prefetchedData = await PLASMIC.maybeFetchComponentData(plasmicPath);

  if (!prefetchedData || prefetchedData.entryCompMetas.length === 0) {
    notFound();
  }

  const prepassHost = process.env.PLASMIC_PREPASS_HOST ?? process.env.VERCEL_URL ?? `http://localhost:${process.env.PORT ?? 3000}`;

  const queryData = await fetchExtractedQueryData(`${prepassHost}/plasmic-ssr/${(params?.catchall ?? []).join("/")}`);

  const pageMeta = prefetchedData.entryCompMetas[0];

  return (
    <PlasmicClientRootProvider
      prefetchedData={prefetchedData}
      prefetchedQueryData={queryData}
      pageParams={pageMeta.params}
    >
      <PlasmicComponent
        component={pageMeta.displayName}
      />
    </PlasmicClientRootProvider>
  )
}

Here, fetchExtractedQueryData() basically just hits the /plasmic-ssr/ endpoint, and extracts the data from the json embedded in the <script/>.

The prepassHost to use is read from PLASMIC_PREPASS_HOST or VERCEL_URL. VERCEL_URL is available when your site is deployed on Vercel; it is the generated deployment url.

@plasmicapp/nextjs-app-router-experimental also comes with a with-plasmic-prepass command that you can use like this in your package.json:

"script": {
  "build": "with-plasmic-prepass -- next build"
}

This script will start up the next dev server at some random port (by running npm run dev), run the passed command, and then kill the dev server. It will run the command with the proper PLASMIC_PREPASS_HOST env variable, so the user never needs to think about it. You can choose to use a different package.json script command to start the dev server via with-plasmic-prepass -c prepass -- next build.

Another annoying bit of something is that the dev server and the build process will step on each other's toes, so you need to direct them to use different output folders. You do it in next.config.js:

module.exports = {
  distDir: process.env.PLASMIC_PREPASS_SERVER ? ".next-prepass" : ".next"
}

The PLASMIC_PREPASS_SERVER environment variable will be set by with-plasmic-prepass.

So...

  • At dev time, uses itself for extracting query data (hits localhost:${PORT})
  • At build time, we start a parallel dev server.
  • In production, with revalidation, it will also use itself for extracting query data (using VERCEL_URL as the prepass host).

Some annoying things here, like:

  • The obnoxious setup!
  • You have to keep plasmic-ssr/ and the real page files "in sync" somewhat. But I guess that's only a bit worse than when you had to do the same for getStaticProps().
  • If they have a super complicated setup where it's hard to bring up the dev server, then... well they'll have to roll their own, following what we did here.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published