TanStackT
TanStack12mo ago
2 replies
wet-aqua

Help! 30 seconds to first paint

I must be doing something upside down and inside out. When loading fresh (no local cache, etc.), my app can take up to 30s before it's actually rendered.

Instrumenting the performance hasn't revealed anything obvious. In fact, some of the time the browser reports that the initial frame renders in <1s although nothing is visible until 20-30seconds later.

Any tips on how to investigate and debug this would be super helpful! Here's an example of a typical route in my app:

// router.ts
import { createRouter as createTanStackRouter } from "@tanstack/react-router";
import { QueryClient } from "@tanstack/react-query";
import { routerWithQueryClient } from "@tanstack/react-router-with-query";
import { ConvexQueryClient } from "@convex-dev/react-query";
import { routeTree } from "./routeTree.gen";
import { ConvexAuthProvider } from "@convex-dev/auth/react";

export function createRouter() {
  let CONVEX_URL = import.meta.env.VITE_CONVEX_URL_DEV;
  const convexQueryClient = new ConvexQueryClient(CONVEX_URL);

  const queryClient: QueryClient = new QueryClient({
    defaultOptions: {
      queries: {
        queryKeyHashFn: convexQueryClient.hashFn(),
        queryFn: convexQueryClient.queryFn(),
      },
    },
  });
  convexQueryClient.connect(queryClient);

  const router = routerWithQueryClient(
    createTanStackRouter({
      routeTree,
      defaultPreload: "intent",
      defaultPendingMinMs: 0, //failed attempt to fix slow render
      defaultPreloadStaleTime: 0, //failed attempt to fix slow render
      defaultNotFoundComponent: () => <div>404</div>,
      context: {
        queryClient,
        auth: undefined!,
      },
      Wrap: ({ children }) => {
        return (
          <ConvexAuthProvider client={convexQueryClient.convexClient}>
            {children}
          </ConvexAuthProvider>
        );
      },
    }),
    queryClient
  );

  return router;
}

declare module "@tanstack/react-router" {
  interface Register {
    router: ReturnType<typeof createRouter>;
  }
}


// routes/_authenticated/route.tsx (VERY SLOW)
import { AppSidebar } from "@/components/app-sidebar";
import { TSRBreadCrumbs } from "@/components/breadcrumbs/breadcrumbs";
import { Separator } from "@/components/ui/separator";
import {
  SidebarInset,
  SidebarProvider,
  SidebarTrigger,
} from "@/components/ui/sidebar";
import { api } from "@/convex/_generated/api";
import { withAuth } from "@/hooks/with-auth";
import { convexQuery } from "@convex-dev/react-query";
import { createFileRoute, Outlet, useNavigate } from "@tanstack/react-router";
import { Authenticated } from "convex/react";
import { useEffect } from "react";

export const Route = createFileRoute("/_authenticated")({
  component: AppWrapper,
  loader(ctx) {
    ctx.context.queryClient.ensureQueryData(
      convexQuery(api.authentication.queries.getMe, {})
    );
  },
});

function AppWrapper() {
  const { isAuthenticated, isLoading } = withAuth();
  const navigate = useNavigate({ from: "/" });

  useEffect(() => {
    if (!isAuthenticated && !isLoading) {
      navigate({
        to: "/login",
      });
    }
  }, [isAuthenticated, isLoading, navigate]);

  if (isLoading) {
    return null;
  }

  return (
    <Authenticated>
      <SidebarProvider name="main">
        <AppSidebar />
        <SidebarInset>
          <header className="flex h-16 shrink-0 items-center gap-2 transition-[width,height] ease-linear group-has-[[data-collapsible=icon]]/sidebar-wrapper:h-12">
            <div className="flex items-center gap-2 px-4">
              <SidebarTrigger className="-ml-1" />
              <Separator orientation="vertical" className="mr-2 h-4" />
              <TSRBreadCrumbs />
            </div>
          </header>
          <div className="flex flex-1 flex-col gap-4 p-0">
            <main>
              <Outlet />
            </main>
          </div>
        </SidebarInset>
      </SidebarProvider>
    </Authenticated>
  );
}
Was this page helpful?