From 8d6dc37b9e84d3866ba1ef2cfce5567eaad7f89e Mon Sep 17 00:00:00 2001 From: Thomas Cristina de Carvalho Date: Sun, 19 Nov 2023 00:20:14 -0500 Subject: [PATCH] Separate sanity server loader from client loader Add hard redirect to revalidate data --- .../app/components/sanity/VisualEditing.tsx | 14 +++------ .../app/hooks/useSanityClient.tsx | 19 ++++++++++++ .../app/hooks/useSanityLoader.tsx | 13 ++++++++ .../app/hooks/useSanityQuery.tsx | 4 +-- .../hydrogen-theme/app/lib/sanity/client.ts | 13 ++++++-- .../app/lib/sanity/sanity.loader.ts | 7 ----- .../app/lib/sanity/sanity.server.ts | 30 ++++++++++++------- templates/hydrogen-theme/app/root.tsx | 8 +++-- .../hydrogen-theme/app/routes/($locale).$.tsx | 1 + .../app/routes/sanity.preview.tsx | 9 +++--- templates/hydrogen-theme/remix.env.d.ts | 1 + templates/hydrogen-theme/server.ts | 3 ++ 12 files changed, 83 insertions(+), 39 deletions(-) create mode 100644 templates/hydrogen-theme/app/hooks/useSanityClient.tsx create mode 100644 templates/hydrogen-theme/app/hooks/useSanityLoader.tsx delete mode 100644 templates/hydrogen-theme/app/lib/sanity/sanity.loader.ts diff --git a/templates/hydrogen-theme/app/components/sanity/VisualEditing.tsx b/templates/hydrogen-theme/app/components/sanity/VisualEditing.tsx index 40799ec..9308dc9 100644 --- a/templates/hydrogen-theme/app/components/sanity/VisualEditing.tsx +++ b/templates/hydrogen-theme/app/components/sanity/VisualEditing.tsx @@ -5,9 +5,9 @@ import { enableOverlays } from "@sanity/overlays"; import { cx } from "class-variance-authority"; import { useEnvironmentVariables } from "~/hooks/useEnvironmentVariables"; -import { getSanityClient } from "~/lib/sanity/client"; -import { useLiveMode } from "~/lib/sanity/sanity.loader"; import { useIsInIframe } from "~/hooks/useIsInIframe"; +import { useSanityClient } from "~/hooks/useSanityClient"; +import { useSanityLoader } from "~/hooks/useSanityLoader"; export function VisualEditing() { const env = useEnvironmentVariables(); @@ -18,14 +18,8 @@ export function VisualEditing() { null ); const sanityStudioUrl = env?.SANITY_STUDIO_URL!; - const { client } = getSanityClient({ - projectId: env?.SANITY_STUDIO_PROJECT_ID!, - dataset: env?.SANITY_STUDIO_DATASET!, - studioUrl: sanityStudioUrl, - useStega: env?.SANITY_STUDIO_USE_STEGA!, - apiVersion: env?.SANITY_STUDIO_API_VERSION!, - useCdn: env?.NODE_ENV === "production", - }); + const client = useSanityClient(); + const { useLiveMode } = useSanityLoader(); useEffect(() => { if (!sanityStudioUrl) return; diff --git a/templates/hydrogen-theme/app/hooks/useSanityClient.tsx b/templates/hydrogen-theme/app/hooks/useSanityClient.tsx new file mode 100644 index 0000000..72deb58 --- /dev/null +++ b/templates/hydrogen-theme/app/hooks/useSanityClient.tsx @@ -0,0 +1,19 @@ +import { getSanityClient } from "~/lib/sanity/client"; +import { useEnvironmentVariables } from "./useEnvironmentVariables"; +import { useSanityPreviewMode } from "./useSanityPreviewMode"; + +export function useSanityClient() { + const env = useEnvironmentVariables(); + const sanityPreviewMode = useSanityPreviewMode(); + const { client } = getSanityClient({ + projectId: env?.SANITY_STUDIO_PROJECT_ID!, + dataset: env?.SANITY_STUDIO_DATASET!, + studioUrl: env?.SANITY_STUDIO_URL!, + useStega: env?.SANITY_STUDIO_USE_STEGA!, + apiVersion: env?.SANITY_STUDIO_API_VERSION!, + useCdn: env?.NODE_ENV === "production", + sanityPreviewMode, + }); + + return client; +} diff --git a/templates/hydrogen-theme/app/hooks/useSanityLoader.tsx b/templates/hydrogen-theme/app/hooks/useSanityLoader.tsx new file mode 100644 index 0000000..3661b61 --- /dev/null +++ b/templates/hydrogen-theme/app/hooks/useSanityLoader.tsx @@ -0,0 +1,13 @@ +import { createQueryStore } from "@sanity/react-loader"; +import { useSanityClient } from "./useSanityClient"; + +export function useSanityLoader() { + const client = useSanityClient(); + const queryStore = createQueryStore({ + client, + ssr: false, + }); + const { useLiveMode, useQuery } = queryStore; + + return { queryStore, useLiveMode, useQuery }; +} diff --git a/templates/hydrogen-theme/app/hooks/useSanityQuery.tsx b/templates/hydrogen-theme/app/hooks/useSanityQuery.tsx index 983a055..5a23057 100644 --- a/templates/hydrogen-theme/app/hooks/useSanityQuery.tsx +++ b/templates/hydrogen-theme/app/hooks/useSanityQuery.tsx @@ -1,7 +1,6 @@ import type { QueryParams } from "@sanity/client/stega"; import type { QueryStoreState, UseQueryOptions } from "@sanity/react-loader"; - -import { useQuery } from "~/lib/sanity/sanity.loader"; +import { useSanityLoader } from "./useSanityLoader"; export function useSanityQuery(cms: { initial: UseQueryOptions["initial"]; @@ -9,6 +8,7 @@ export function useSanityQuery(cms: { query: string; }): QueryStoreState { const { initial, params, query } = cms; + const { useQuery } = useSanityLoader(); return useQuery(query, params, { initial, diff --git a/templates/hydrogen-theme/app/lib/sanity/client.ts b/templates/hydrogen-theme/app/lib/sanity/client.ts index 638d4e0..fc4ad47 100644 --- a/templates/hydrogen-theme/app/lib/sanity/client.ts +++ b/templates/hydrogen-theme/app/lib/sanity/client.ts @@ -8,8 +8,17 @@ export const getSanityClient = (args: { studioUrl: string; apiVersion: string; useCdn: boolean; + sanityPreviewMode?: boolean; }) => { - const { projectId, dataset, useStega, studioUrl, apiVersion, useCdn } = args; + const { + projectId, + dataset, + useStega, + studioUrl, + apiVersion, + useCdn, + sanityPreviewMode, + } = args; return { client: createClient({ @@ -18,7 +27,7 @@ export const getSanityClient = (args: { useCdn, apiVersion: apiVersion || "2023-10-01", stega: { - enabled: useStega === "true" ? true : false, + enabled: sanityPreviewMode && useStega === "true" ? true : false, studioUrl, }, }), diff --git a/templates/hydrogen-theme/app/lib/sanity/sanity.loader.ts b/templates/hydrogen-theme/app/lib/sanity/sanity.loader.ts deleted file mode 100644 index 38e38f8..0000000 --- a/templates/hydrogen-theme/app/lib/sanity/sanity.loader.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { createQueryStore } from "@sanity/react-loader"; - -// This is the "smallest" possible version of a query store -// Where stega-enabled queries only happen server-side to avoid bundle bloat -export const queryStore = createQueryStore({ client: false, ssr: true }); - -export const { useLiveMode, useQuery } = queryStore; diff --git a/templates/hydrogen-theme/app/lib/sanity/sanity.server.ts b/templates/hydrogen-theme/app/lib/sanity/sanity.server.ts index 7ac6141..7dfe697 100644 --- a/templates/hydrogen-theme/app/lib/sanity/sanity.server.ts +++ b/templates/hydrogen-theme/app/lib/sanity/sanity.server.ts @@ -9,12 +9,13 @@ import type { } from "@sanity/client/stega"; import { CacheShort, createWithCache } from "@shopify/hydrogen"; -import { queryStore } from "./sanity.loader"; import { getSanityClient } from "./client"; +import { createQueryStore } from "@sanity/react-loader"; type CreateSanityClientOptions = { cache: Cache; waitUntil: ExecutionContext["waitUntil"]; + sanityPreviewMode: boolean; config: { projectId: string; dataset: string; @@ -45,13 +46,10 @@ export type Sanity = { }>; }; -let sanityServerClientHasBeenInitialized = false; - export function createSanityClient(options: CreateSanityClientOptions) { - const { cache, waitUntil, config } = options; + const { cache, waitUntil, config, sanityPreviewMode } = options; const { projectId, dataset, useStega, useCdn, studioUrl, apiVersion } = config; - const { loadQuery } = queryStore; const { client } = getSanityClient({ projectId, @@ -60,12 +58,13 @@ export function createSanityClient(options: CreateSanityClientOptions) { apiVersion, useStega, studioUrl, + sanityPreviewMode, }); - if (!sanityServerClientHasBeenInitialized) { - queryStore.setServerClient(client); - sanityServerClientHasBeenInitialized = true; - } + const queryStore = createQueryStore({ + client, + ssr: false, + }); const sanity: Sanity = { client, @@ -75,8 +74,9 @@ export function createSanityClient(options: CreateSanityClientOptions) { cache: strategy = CacheShort(), queryOptions, }) { + const { loadQuery } = queryStore; const { query } = groqdQuery as GroqdQuery; - const queryHash = await hashQuery(query, params); + const queryHash = await hashQuery(query, params, sanityPreviewMode); const withCache = createWithCache({ cache, waitUntil, @@ -119,9 +119,17 @@ export async function sha256(message: string): Promise { * Hash query and its parameters for use as cache key * NOTE: Oxygen deployment will break if the cache key is long or contains `\n` */ -function hashQuery(query: GroqdQuery["query"], params?: QueryParams) { +function hashQuery( + query: GroqdQuery["query"], + params?: QueryParams, + sanityPreviewMode?: boolean +) { let hash = query; + if (sanityPreviewMode) { + hash += "previewMode"; + } + if (params !== null) { hash += JSON.stringify(params); } diff --git a/templates/hydrogen-theme/app/root.tsx b/templates/hydrogen-theme/app/root.tsx index 98a0e86..644c417 100644 --- a/templates/hydrogen-theme/app/root.tsx +++ b/templates/hydrogen-theme/app/root.tsx @@ -23,6 +23,7 @@ import { Fonts } from "./components/Fonts"; import { CMS_SETTINGS_QUERY } from "./qroq/queries"; import { generateFontsPreloadLinks } from "./lib/fonts"; import { useLocale } from "./hooks/useLocale"; +import { vercelStegaCleanAll } from "@sanity/client/stega"; // This is important to avoid re-fetching root queries on sub-navigations export const shouldRevalidate: ShouldRevalidateFunction = ({ @@ -78,9 +79,8 @@ export const meta: MetaFunction = (loaderData) => { }; export async function loader({ context }: LoaderFunctionArgs) { - const { session, cart, env, sanity, locale, sanitySession } = context; + const { session, cart, env, sanity, locale, sanityPreviewMode } = context; const customerAccessToken = await session.get("customerAccessToken"); - const sanityPreviewMode = await sanitySession.has("previewMode"); const cmsSettings = await sanity.query({ groqdQuery: CMS_SETTINGS_QUERY, @@ -100,7 +100,9 @@ export async function loader({ context }: LoaderFunctionArgs) { locale, sanityPreviewMode, cms: { - initial: cmsSettings, + initial: sanityPreviewMode + ? cmsSettings + : vercelStegaCleanAll(cmsSettings), query: CMS_SETTINGS_QUERY.query, params: {}, }, diff --git a/templates/hydrogen-theme/app/routes/($locale).$.tsx b/templates/hydrogen-theme/app/routes/($locale).$.tsx index ff99982..93aff98 100644 --- a/templates/hydrogen-theme/app/routes/($locale).$.tsx +++ b/templates/hydrogen-theme/app/routes/($locale).$.tsx @@ -7,6 +7,7 @@ import type { I18nLocale } from "~/lib/type"; import { CmsSection } from "~/components/CmsSection"; import { PAGE_QUERY } from "~/qroq/queries"; import { useSanityQuery } from "~/hooks/useSanityQuery"; +import { useSanityPreviewMode } from "~/hooks/useSanityPreviewMode"; export async function loader({ context, params, request }: LoaderFunctionArgs) { const { sanity, locale } = context; diff --git a/templates/hydrogen-theme/app/routes/sanity.preview.tsx b/templates/hydrogen-theme/app/routes/sanity.preview.tsx index 009be1b..63348de 100644 --- a/templates/hydrogen-theme/app/routes/sanity.preview.tsx +++ b/templates/hydrogen-theme/app/routes/sanity.preview.tsx @@ -2,13 +2,14 @@ import type { ActionFunctionArgs, LoaderFunctionArgs, } from "@shopify/remix-oxygen"; -import { json, redirect } from "@shopify/remix-oxygen"; +import { json, redirectDocument } from "@shopify/remix-oxygen"; + import { notFound } from "~/lib/utils"; const ROOT_PATH = "/" as const; export async function action({ context, request }: ActionFunctionArgs) { - const { sanitySession, env } = context; + const { sanitySession } = context; if (!(request.method === "POST" && sanitySession)) { return json({ message: "Method not allowed" }, 405); @@ -18,7 +19,7 @@ export async function action({ context, request }: ActionFunctionArgs) { const slug = (body.get("slug") as string) ?? ROOT_PATH; const redirectTo = slug; - return redirect(redirectTo, { + return redirectDocument(redirectTo, { headers: { "Set-Cookie": await sanitySession.destroy(), }, @@ -43,7 +44,7 @@ export async function loader({ context, request }: LoaderFunctionArgs) { "Set-Cookie": useStega ? await sanitySession.commit() : "", }; - return redirect(redirectTo, { + return redirectDocument(redirectTo, { status: 307, headers, }); diff --git a/templates/hydrogen-theme/remix.env.d.ts b/templates/hydrogen-theme/remix.env.d.ts index d3e4071..ffeb9a3 100644 --- a/templates/hydrogen-theme/remix.env.d.ts +++ b/templates/hydrogen-theme/remix.env.d.ts @@ -49,6 +49,7 @@ declare module "@shopify/remix-oxygen" { storefront: Storefront; session: HydrogenSession; sanitySession: SanitySession; + sanityPreviewMode: boolean; waitUntil: ExecutionContext["waitUntil"]; sanity: Sanity; locale: I18nLocale; diff --git a/templates/hydrogen-theme/server.ts b/templates/hydrogen-theme/server.ts index ee10c02..4d0af69 100644 --- a/templates/hydrogen-theme/server.ts +++ b/templates/hydrogen-theme/server.ts @@ -46,6 +46,7 @@ export default { HydrogenSession.init(request, [env.SESSION_SECRET]), SanitySession.init(request, [env.SESSION_SECRET]), ]); + const sanityPreviewMode = await sanitySession.has("previewMode"); /* * Create Hydrogen's Storefront client. @@ -79,6 +80,7 @@ export default { const sanity = createSanityClient({ cache, waitUntil, + sanityPreviewMode, config: { projectId: envVars.SANITY_STUDIO_PROJECT_ID, dataset: envVars.SANITY_STUDIO_DATASET, @@ -99,6 +101,7 @@ export default { getLoadContext: () => ({ session, sanitySession, + sanityPreviewMode, storefront, cart, env: envVars,