perf: Use one PageWrapper instance for every non-settings / non-bookings page in App Router (#18747)

* add a layoutfile to use-page-wrapper route group

* refactor and move bookings status page to route group

* improve logic in pagesAndRewritePaths

* fix

* add use client directive

* move /403 and /500

* move /auth/error

* move /connect-and-join

* move /enterprise

* move /maintenance

* move /more

* move /upgrade

* chore: remove WithLayout from 8 low-risk single pages (#18745)

* move /403 and /500

* move /auth/error

* move /connect-and-join

* move /enterprise

* move /maintenance

* move /more

* move /upgrade

* move /availability pages

* move /event-types pages

* move /insights pages

* move /apps to use-page-wrapper group

* move /getting-started to use-page-wrapper group

* move /signup to use-page-wrapper group

* move /workflows to use-page-wrapper group

* move /video pages to use-page-wrapper group

* pass dehydratedState in layout

* pass dehydratedState in layout

* fix test

* fix @test

* fix
This commit is contained in:
Benny Joo
2025-01-23 10:01:46 -05:00
committed by GitHub
parent 2335aba843
commit 8e191fed71
26 changed files with 164 additions and 127 deletions
@@ -0,0 +1,27 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { getServerSideProps } from "@lib/apps/getServerSideProps";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import AppsPage from "~/apps/apps-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => t("app_store"),
(t) => t("app_store_description")
);
};
const getData = withAppDirSsr(getServerSideProps);
const ServerPage = async ({ params, searchParams }: PageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <AppsPage {...props} />;
};
export default ServerPage;
@@ -1,6 +1,5 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { notFound } from "next/navigation";
import { cache } from "react";
import { z } from "zod";
@@ -89,4 +88,4 @@ const Page = async ({ params }: PageProps) => {
);
};
export default WithLayout({ ServerPage: Page });
export default Page;
@@ -1,5 +1,4 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { notFound } from "next/navigation";
// import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
@@ -36,4 +35,4 @@ const Page = async () => {
}
};
export default WithLayout({ ServerPage: Page });
export default Page;
@@ -0,0 +1,15 @@
"use client";
import React, { Suspense } from "react";
import { ErrorBoundary, Icon } from "@calcom/ui";
export default function TroubleshooterLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex flex-1 [&>*]:flex-1">
<ErrorBoundary>
<Suspense fallback={<Icon name="loader" />}>{children}</Suspense>
</ErrorBoundary>
</div>
);
}
@@ -1,7 +1,6 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import Troubleshoot, { getLayout } from "~/availability/troubleshoot/troubleshoot-view";
import Troubleshoot from "~/availability/troubleshoot/troubleshoot-view";
export const generateMetadata = async () => {
return await _generateMetadata(
@@ -10,4 +9,4 @@ export const generateMetadata = async () => {
);
};
export default WithLayout({ getLayout, Page: Troubleshoot });
export default Troubleshoot;
@@ -1,15 +1,15 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps } from "app/_types";
import type { PageProps as _PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import type { PageProps as EventTypePageProps } from "@lib/event-types/[type]/getServerSideProps";
import { getServerSideProps } from "@lib/event-types/[type]/getServerSideProps";
import EventTypePageWrapper from "~/event-types/views/event-types-single-view";
export const generateMetadata = async ({ params, searchParams }: PageProps) => {
export const generateMetadata = async ({ params, searchParams }: _PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const { eventType } = await getData(legacyCtx);
@@ -19,6 +19,13 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
);
};
const getData = withAppDirSsr(getServerSideProps);
const getData = withAppDirSsr<EventTypePageProps>(getServerSideProps);
export default WithLayout({ getLayout: null, getData, Page: EventTypePageWrapper })<"P">;
const ServerPage = async ({ params, searchParams }: _PageProps) => {
const legacyCtx = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(legacyCtx);
return <EventTypePageWrapper {...props} />;
};
export default ServerPage;
@@ -1,6 +1,5 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation";
@@ -30,4 +29,4 @@ const Page = async ({ params, searchParams }: PageProps) => {
return <EventTypes />;
};
export default WithLayout({ ServerPage: Page })<"P">;
export default Page;
@@ -0,0 +1,31 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as ServerPageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { APP_NAME } from "@calcom/lib/constants";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps";
import type { PageProps as ClientPageProps } from "~/getting-started/[[...step]]/onboarding-view";
import Page from "~/getting-started/[[...step]]/onboarding-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => `${APP_NAME} - ${t("getting_started")}`,
() => "",
true
);
};
const getData = withAppDirSsr<ClientPageProps>(getServerSideProps);
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <Page {...props} />;
};
export default ServerPage;
@@ -1,18 +1,17 @@
"use client";
import type { ReactElement } from "react";
import { useSession } from "next-auth/react";
import Shell from "@calcom/features/shell/Shell";
import { UpgradeTip } from "@calcom/features/tips";
import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { Button, ButtonGroup } from "@calcom/ui";
import { Icon } from "@calcom/ui";
export default function InsightsLayout({ children }: { children: React.ReactNode }) {
const { t } = useLocale();
const { data: user } = trpc.viewer.me.useQuery();
const session = useSession();
const features = [
{
@@ -59,11 +58,9 @@ export default function InsightsLayout({ children }: { children: React.ReactNode
</ButtonGroup>
</div>
}>
{!user ? null : children}
{!session.data?.user ? null : children}
</UpgradeTip>
</Shell>
</div>
);
}
export const getInsightsLayout = (page: ReactElement) => <InsightsLayout>{page}</InsightsLayout>;
@@ -1,7 +1,10 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/signup/getServerSideProps";
import type { SignupProps } from "~/signup-view";
@@ -15,8 +18,11 @@ export const generateMetadata = async () =>
const getData = withAppDirSsr<SignupProps>(getServerSideProps);
export default WithLayout({
Page: Signup,
getLayout: null,
getData,
})<"P">;
const ServerPage = async ({ params, searchParams }: PageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <Signup {...props} />;
};
export default ServerPage;
@@ -1,12 +1,14 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as ServerPageProps } from "app/_types";
import { getTranslate } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { APP_NAME, SEO_IMG_OGIMG_VIDEO, WEBSITE_URL } from "@calcom/lib/constants";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/video/[uid]/getServerSideProps";
import type { PageProps } from "~/videos/views/videos-single-view";
import type { PageProps as ClientPageProps } from "~/videos/views/videos-single-view";
import VideosSingleView from "~/videos/views/videos-single-view";
export const generateMetadata = async () => {
@@ -34,6 +36,13 @@ export const generateMetadata = async () => {
};
};
const getData = withAppDirSsr<PageProps>(getServerSideProps);
const getData = withAppDirSsr<ClientPageProps>(getServerSideProps);
export default WithLayout({ getData, Page: VideosSingleView, getLayout: null })<"P">;
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <VideosSingleView {...props} />;
};
export default ServerPage;
@@ -0,0 +1,27 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { PageProps as ServerPageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { cookies, headers } from "next/headers";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/video/meeting-ended/[uid]/getServerSideProps";
import type { PageProps as ClientPageProps } from "~/videos/views/videos-meeting-ended-single-view";
import MeetingEnded from "~/videos/views/videos-meeting-ended-single-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("meeting_unavailable"),
(t) => t("meeting_unavailable")
);
const getData = withAppDirSsr<ClientPageProps>(getServerSideProps);
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <MeetingEnded {...props} />;
};
export default ServerPage;
@@ -1,22 +1,23 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import type { PageProps as _PageProps } from "app/_types";
import type { PageProps as ServerPageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { cookies, headers } from "next/headers";
import { notFound } from "next/navigation";
import { z } from "zod";
import { BookingRepository } from "@calcom/lib/server/repository/booking";
import { buildLegacyCtx } from "@lib/buildLegacyCtx";
import { getServerSideProps } from "@lib/video/meeting-not-started/[uid]/getServerSideProps";
import type { PageProps } from "~/videos/views/videos-meeting-not-started-single-view";
import type { PageProps as ClientPageProps } from "~/videos/views/videos-meeting-not-started-single-view";
import MeetingNotStarted from "~/videos/views/videos-meeting-not-started-single-view";
const querySchema = z.object({
uid: z.string(),
});
export const generateMetadata = async ({ params }: _PageProps) => {
export const generateMetadata = async ({ params }: ServerPageProps) => {
const parsed = querySchema.safeParse(params);
if (!parsed.success) {
notFound();
@@ -31,6 +32,13 @@ export const generateMetadata = async ({ params }: _PageProps) => {
);
};
const getData = withAppDirSsr<PageProps>(getServerSideProps);
const getData = withAppDirSsr<ClientPageProps>(getServerSideProps);
export default WithLayout({ getData, Page: MeetingNotStarted, getLayout: null })<"P">;
const ServerPage = async ({ params, searchParams }: ServerPageProps) => {
const context = buildLegacyCtx(headers(), cookies(), params, searchParams);
const props = await getData(context);
return <MeetingNotStarted {...props} />;
};
export default ServerPage;
@@ -1,5 +1,4 @@
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import NoMeetingFound from "~/videos/views/videos-no-meeting-found-single-view";
@@ -9,4 +8,4 @@ export const generateMetadata = async () =>
(t) => t("no_meeting_found")
);
export default WithLayout({ Page: NoMeetingFound, getLayout: null })<"P">;
export default NoMeetingFound;
@@ -1,6 +1,5 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import type { Metadata } from "next";
import { notFound } from "next/navigation";
import { cache } from "react";
@@ -70,7 +69,7 @@ const Page = async ({ params }: PageProps) => {
);
};
export default WithLayout({ getLayout: null, ServerPage: Page });
export default Page;
export const dynamic = "force-static";
// generate segments on demand
export const dynamicParams = true;
@@ -1,6 +1,5 @@
import type { PageProps } from "app/_types";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
// import { getServerSessionForAppDir } from "@calcom/feature-auth/lib/get-server-session-for-app-dir";
// import { getTeamsFiltersFromQuery } from "@calcom/features/filters/lib/getTeamsFiltersFromQuery";
@@ -37,4 +36,4 @@ const Page = async ({ params, searchParams }: PageProps) => {
);
};
export default WithLayout({ getLayout: null, ServerPage: Page })<"P">;
export default Page;
-19
View File
@@ -1,19 +0,0 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@lib/apps/getServerSideProps";
import AppsPage from "~/apps/apps-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => t("app_store"),
(t) => t("app_store_description")
);
};
export default WithLayout({
getData: withAppDirSsr(getServerSideProps),
Page: AppsPage,
});
@@ -1,24 +0,0 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { APP_NAME } from "@calcom/lib/constants";
import { getServerSideProps } from "@lib/getting-started/[[...step]]/getServerSideProps";
import type { PageProps } from "~/getting-started/[[...step]]/onboarding-view";
import Page from "~/getting-started/[[...step]]/onboarding-view";
export const generateMetadata = async () => {
return await _generateMetadata(
(t) => `${APP_NAME} - ${t("getting_started")}`,
() => "",
true
);
};
export default WithLayout({
getLayout: null,
getData: withAppDirSsr<PageProps>(getServerSideProps),
Page,
});
-5
View File
@@ -1,5 +0,0 @@
import { WithLayout } from "app/layoutHOC";
import { getInsightsLayout } from "~/insights/layout";
export default WithLayout({ getLayout: getInsightsLayout });
@@ -1,18 +0,0 @@
import { withAppDirSsr } from "app/WithAppDirSsr";
import { _generateMetadata } from "app/_utils";
import { WithLayout } from "app/layoutHOC";
import { getServerSideProps } from "@lib/video/meeting-ended/[uid]/getServerSideProps";
import type { PageProps } from "~/videos/views/videos-meeting-ended-single-view";
import MeetingEnded from "~/videos/views/videos-meeting-ended-single-view";
export const generateMetadata = async () =>
await _generateMetadata(
(t) => t("meeting_unavailable"),
(t) => t("meeting_unavailable")
);
const getData = withAppDirSsr<PageProps>(getServerSideProps);
export default WithLayout({ getData, Page: MeetingEnded, getLayout: null })<"P">;
@@ -26,6 +26,5 @@ function TroubleshooterPage() {
</>
);
}
export { getLayout } from "@calcom/features/troubleshooter/layout";
export default TroubleshooterPage;
+3
View File
@@ -75,6 +75,9 @@ test.describe("Event Types tests", () => {
const eventTitle = `my recurring event ${nonce}`;
await createNewEventType(page, { eventTitle });
// eslint-disable-next-line playwright/no-wait-for-timeout
await page.waitForTimeout(1000); // waits for 1 second
await page.click("[data-testid=vertical-tab-recurring]");
await expect(page.locator("[data-testid=recurring-event-collapsible]")).toBeHidden();
await page.click("[data-testid=recurring-event-check]");
@@ -1,19 +0,0 @@
import type { ComponentProps } from "react";
import React, { Suspense } from "react";
import type Shell from "@calcom/features/shell/Shell";
import { ErrorBoundary, Icon } from "@calcom/ui";
export default function TroubleshooterLayout({
children,
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
return (
<div className="flex flex-1 [&>*]:flex-1">
<ErrorBoundary>
<Suspense fallback={<Icon name="loader" />}>{children}</Suspense>
</ErrorBoundary>
</div>
);
}
export const getLayout = (page: React.ReactElement) => <TroubleshooterLayout>{page}</TroubleshooterLayout>;