Nuxt3 very slow when logged in to prismic

I've noticed that when I am logged into prismic developing locally (as well as when logged in using production) page transitions jump from instant to almost 3 seconds.

Here's a video demonstrating the speed drop:

Logged in to prismic: http://grfk.co.nz/v/Gu2jOe
Not logged in to prismic: Screen Capture on 2024-06-20 at 09-00-37.mp4 - Droplr

@nuxtjs/prismic": "^3.3.1
"nuxt": "^3.11.1"

Am I doing something wrong here? Why is it so slow when logged in to prismic?

Hi @grafik, this looks weird indeed!

Did you notice this started happening recently or has it always been like that?

Can you share more details about how you query pages in your components? Some example codes perhaps?

Happy to investigate that further with you :slight_smile:

Thanks, it's been happening for a while now, here's how I query code on those example pages.

Projects page (user can select and order projects)

const { data: page } = await useAsyncData("projectsData", async () => {
  const navigation = await prismic.client.getSingle("main_menu");
  const projects = await prismic.client.getSingle("projects");
  const footer = await prismic.client.getSingle("footer");

  const allProjects = await Promise.all(
    projects?.data?.projects.map(async (item) => {
      try {
        const project = await prismic.client.getByID(item?.project?.id);
        if (project === null || project === undefined) {
          throw new Error(`Project with ID ${item.project.id} not found`);
        }

        return {
          ...item,
          projectTitle: project?.data?.page_title,
          projectStatus: project?.data?.status,
          projectIntroduction: project?.data?.introduction,
          projectExcerpt: project?.data?.excerpt,
          projectThumbnail: project?.data?.thumbnail_portrait,
          link: project?.uid,
        };
      } catch (error) {
        console.error(
          `Error fetching project with ID ${item.project.id}:`,
          error
        );
        // Handle the error, e.g., show an error message or take alternative action
        return null;
      }
    })
  );

  return {
    navigation,
    projects,
    footer,
    allProjects,
  };
});

Project Page

const { data: page } = await useAsyncData(route.params.uid, async () => {
  const project = await client.getByUID("project", route.params.uid);
  const navigation = await client.getSingle("main_menu");
  const footer = await client.getSingle("footer");

  if (project) {
    return {
      navigation,
      slices: project.data.slices2,

      footer,
      project,
    };
  } else {
    throw createError({ statusCode: 404, message: "Page not found" });
  }
});

Nothing overtly complex from what I can gather? This happens on all pages, each with different queries.

My gut feeling is that it's something to do with the prismic toolbar, as the slowness only happens when logged in to prismic.

Hi @lihbr I can share my repo as a ZIP file, if that helps you investigate it further?

Hi @lihbr or anyone, just following up on this?

Hi @grafik, I'm so sorry I wasn't available to follow up on your issue last week.

Your code looks fine to me and is identical to the one we have in our starters.

Are you experiencing the same behavior on a production website? (something hosted on Vercel for example), or only in development mode?

I'm happy for you to send me a zip if you want me to have a deeper look at your codebase, feel free to shoot me a mail with it: lucie.haberer@prismic.io

I'll make sure to keep a closer eye at your issue

1 Like

Thanks, yes it also happens in production, the website is hosted on Netlify.

Have sent you a copy of my repo so you can take a look,

Hi @grafik,

I investigated the source code you sent me and managed to reproduce the behavior you're experiencing.

Long story short, this is a normal behavior, but I'll explain what's happening and how to reduce its impact on your website.

What's happening

When logged out of Prismic, the website is able to fetch content of the new page really fast because it's already cached on Cloudflare (you can see a header from the response in the network tab saying Cloudflare cache did hit on each of them)

When connected to Prismic, the website fetches content the same way, but because the toolbar is now loaded it also sets a tracker (it's not an analytics tracker, it just allows us to differentiate your very requests from others). This tracker gets attached to each of your requests to Prismic to enable certain features of the toolbar. Because this tracker gets updated on each page navigation it causes the Cloudflare cache to always miss (which is what we need for the toolbar to function), forcing the request to get fresh data from Prismic directly, which is ultimately slower to resolve.

How to minimize this behavior's impact

Options 1: Going static

It looks like your website is set up in a hybrid mode: it renders the first page on the server and then renders subsequent pages on the client upon navigation

You could reduce the impact of this toolbar's behavior to 0 if you can/want your website to be static. On Netlify this involves updating your build command to be nuxt generate instead of nuxt build. You can try it locally with yarn generate && npx serve .output/public, it did work as expected on my end.

Options 2: Parallelizing your requests

I noticed your requests to Prismic are done in "waterfall" (i.e. one at a time), parallelizing your requests could significantly improve your site's speed when navigating it when connected to Prismic (but it would also improve its build time!)

For example on your index page, you can refactor this code:

const { data: page } = await useAsyncData("homeData", async () => {
  const navigation = await prismic.client.getSingle("main_menu");
  const home = await prismic.client.getSingle("home");
  const footer = await prismic.client.getSingle("footer");

  return {
    navigation,
    home,
    footer,
  };
});

To this:

const { data: page } = await useAsyncData("homeData", async () => {
  const [navigation, home, footer] = await Promise.all([
    prismic.client.getSingle("main_menu"),
    prismic.client.getSingle("home"),
    prismic.client.getSingle("footer"),
  ]);

  return {
    navigation,
    home,
    footer,
  };
});

Using this pattern on all your async data calls could greatly reduce the time required to fetch the content of each of your pages.


Let me know if that's clear enough! Happy to elaborate more as needed :smiling_face:

P.S. Really cool website and nice pictures!

2 Likes

Thank you so much @lihbr for your detailed investigation and explanation, I'll give these suggestions a whirl and comeback with any questions if I have any!

1 Like