Hi @fmota
Thanks for your reply.
After looking into this a lot more, I actually don’t think extractPlasmicQueryData is causing slowness.
The ./pages/[...catchall].tsx
page (code below) fails frequently with a 10 second timeout at the await supabase.auth.getUser()
line, well before we do anything with fetching from Plasmic.
No API call ever reaches Supabase when the timeout occurs, and if I insert a try catch
block within getServerSideProps
no errors occur. It seems to simply timeout at Vercel’s standard 10 second limit pretty often.
Timeout occurs more frequently when navigating or refreshing a page after a period of inactivity. The issue persists even when paying for the first level Vercel plan, rather than relying on the more limited free plan.
I’m wondering if this is occuring because of the large page size of the catchall page? (I frequently get warnings in terminal console when running my local dev server about large page size impacting performance).
An example of a page that times out frequently is this one: Plasmic
This issue is worth noting if you’re wanting to publish example code that uses getServerSideProps() & I’m still really curious about what’s going on. So if you have any further insights, I’d love to hear them.
However, for my project, I’ve transitioned back to the standard [[…catchall]].tsx page generated when you publish Plasmic projects to nextjs with the loader API. And I’m login protecting pages with nextjs middleware instead. This has avoided the issue described above and is a cleaner, simpler, solution for my needs anyway. The plasmic-supabase
repo will be updated accordingly soon to give new instructions on using middleware for login-protecting pages.
Here is the ./pages/[...catchall].tsx
code showing the actual API call to supabase, which is where it times out without any API call sent to Supabase
// ./pages/[...catchall].tsx
/*
Catchall page that runs for every page EXCEPT /, /login, and /public/*
These pages are login protected by default
The logic for checking authorization & where to redirect if a user is not authorized is controlled
by @/authorization-settings.ts.
The authorization-settings.ts file should export:
- authorizationCheckFunction: a function that returns true if the user is authorized to view the page
- loginPagePath: where to redirect to if authorization fails eg '/login'
The routes that render through this page are rendered on-demand (getServerSideProps instead of getStaticProps)
because they are login protected. This ensures that the user's session is checked on every request
and avoids login-protected pages being cached and related issues.
This pages is a modified various of the standard Plasmic NextJS loader API catchall page.
Pages created in Plasmic studio will render using this catchall if it's:
Page Settings -> URL path does NOT start with '/public/' and is not "/" or "/login"
*/
import type { GetServerSideProps } from "next";
import { createClient } from 'plasmic-supabase/dist/utils/supabase/server-props'
import * as React from "react";
import {
PlasmicComponent,
PlasmicRootProvider,
} from "@plasmicapp/loader-nextjs";
import Error from "next/error";
import { useRouter } from "next/router";
import { PLASMIC } from "@/plasmic-init";
import useSWR from "swr";
import { authorizationCheckFunction, loginPagePath } from "@/authorization-settings";
export default function PlasmicLoaderPage(props: {
plasmicPath: string;
}) {
const router = useRouter();
//Fetch the component (page) data from Plasmic and cache it with SWR
//Note that when navigating between [[...catchall]].tsx and this page
//A warning from Plasmic will appear in console https://github.com/plasmicapp/plasmic/blob/7117b4c2de9e89f4435db9efa0cba6a00012c297/packages/loader-react/src/loader-shared.ts#L498
//Because maybeFetchComponentData will fetch designs with query string parameter browserOnly=true here
//But browserOnly=false from [[...catchall]].tsx
//Because fetching of Plasmic componet data is happening client side here, but server side in [[...catchall]].tsx
//This does not appear to matter since the referenced file above seems to gracefully handle this case
//However if the error could be removed by some refactor, it would be ideal
const plasmicComponentFetcher = React.useCallback(async () => {
return await PLASMIC.maybeFetchComponentData(props.plasmicPath);
}, [props.plasmicPath]);
const { data: plasmicData, error, isValidating } = useSWR(
`plasmicData_${props.plasmicPath}`,
plasmicComponentFetcher
);
//Render the error page if there is an error
if(error) {
return <Error statusCode={500} />;
}
//Render a loading message if the data is still loading
if(isValidating && !plasmicData) {
return <div>Loading...</div>;
}
//Render a 404 page if the page is not found in Plasmic
if ((!isValidating && (!plasmicData || plasmicData.entryCompMetas.length === 0))) {
return <Error statusCode={404} />;
}
//Extract the page meta data from the Plasmic data
const pageMeta = plasmicData!.entryCompMetas[0]
//Render the Plasmic component (page)
return (
<PlasmicRootProvider
loader={PLASMIC}
prefetchedData={plasmicData!}
prefetchedQueryData={{}}
pageParams={pageMeta.params}
pageQuery={router.query}
>
<PlasmicComponent component={pageMeta.displayName} />
</PlasmicRootProvider>
);
}
//This runs on the server while rendering
//Unlike the pages in the root directory, we run this every time the page is requested with no cache
//This is appropriate because these pages are login protected and only work with a valid session
//We also need to recheck each time the page is requested to ensure the user is still authenticated
export const getServerSideProps: GetServerSideProps = async (context) => {
//Get the catchall parameter from the page context
const { catchall } = context.params ?? {};
//Get the path of the current page
let plasmicPath = typeof catchall === 'string' ? catchall : Array.isArray(catchall) ? `/${catchall.join('/')}` : '/';
//Determine if the user is authorized to view this page
const supabase = createClient(context);
const { data: { user } } = await supabase.auth.getUser();
const isAuthorized = authorizationCheckFunction(plasmicPath, user);
if(isAuthorized !== true) return {
redirect: {
destination: loginPagePath,
permanent: false,
}
}
//We don't try and fetch the plasmic component data or data on the page here, because getServerSideProps does not cache
//Therefore we would run this every time without cache, causing slow page navigation
//Instead, we do that client-side and cache results with SWR (see above)
return { props: { plasmicPath } };
}