From 41284da1ecb05babfbac35cdd5f07e5fad84fd09 Mon Sep 17 00:00:00 2001 From: Yasuaki Goto Date: Sun, 27 Nov 2022 14:30:14 +0900 Subject: [PATCH] Add support for typed-document-node --- .changeset/wild-rivers-refuse.md | 5 ++++ .../hydrogen/src/hooks/useShopQuery/hooks.ts | 17 ++++++++++---- packages/hydrogen/src/utilities/apiRoutes.ts | 23 ++++++++++++------- 3 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 .changeset/wild-rivers-refuse.md diff --git a/.changeset/wild-rivers-refuse.md b/.changeset/wild-rivers-refuse.md new file mode 100644 index 0000000000..9b69fed419 --- /dev/null +++ b/.changeset/wild-rivers-refuse.md @@ -0,0 +1,5 @@ +--- +'@shopify/hydrogen': minor +--- + +Add support for @graphql-typed-document-node diff --git a/packages/hydrogen/src/hooks/useShopQuery/hooks.ts b/packages/hydrogen/src/hooks/useShopQuery/hooks.ts index 87e01bb2f1..1c8fe27bd1 100644 --- a/packages/hydrogen/src/hooks/useShopQuery/hooks.ts +++ b/packages/hydrogen/src/hooks/useShopQuery/hooks.ts @@ -11,6 +11,8 @@ import {getStorefrontApiRequestHeaders} from '../../utilities/storefrontApi.js'; import {parseJSON} from '../../utilities/parse.js'; import {useQuery} from '../../foundation/useQuery/hooks.js'; import {HydrogenRequest} from '../../foundation/HydrogenRequest/HydrogenRequest.server.js'; +import {TypedDocumentNode} from '@graphql-typed-document-node/core'; +import {print} from 'graphql'; export interface UseShopQueryResponse { /** The data returned by the query. */ @@ -27,7 +29,7 @@ const shouldCacheResponse = (body: any) => { /** * The `useShopQuery` hook allows you to make server-only GraphQL queries to the Storefront API. It must be a descendent of a `ShopifyProvider` component. */ -export function useShopQuery({ +export function useShopQuery = {}>({ query, variables = {}, cache, @@ -36,7 +38,7 @@ export function useShopQuery({ /** A string of the GraphQL query. * If no query is provided, useShopQuery will make no calls to the Storefront API. */ - query?: string; + query?: string | TypedDocumentNode; /** An object of the variables for the GraphQL query. */ variables?: Record; /** The [caching strategy](https://shopify.dev/custom-storefronts/hydrogen/querying/cache#caching-strategies) to @@ -50,12 +52,12 @@ export function useShopQuery({ * to preload the query for all requests. */ preload?: PreloadOptions; -}): UseShopQueryResponse { +}): UseShopQueryResponse { /** * If no query is passed, we no-op here to allow developers to obey the Rules of Hooks. */ if (!query) { - return {data: undefined as unknown as T, errors: undefined}; + return {data: undefined as unknown as Data, errors: undefined}; } if (!META_ENV_SSR) { @@ -75,7 +77,12 @@ export function useShopQuery({ privateStorefrontToken, } = useShop(); - const body = query ? graphqlRequestBody(query, variables) : ''; + const body = query + ? graphqlRequestBody( + typeof query === 'string' ? query : print(query), + variables + ) + : ''; const {data, error} = useQuery( [storeDomain, storefrontApiVersion, body], diff --git a/packages/hydrogen/src/utilities/apiRoutes.ts b/packages/hydrogen/src/utilities/apiRoutes.ts index 4b97caa67b..da3a5d9fa9 100644 --- a/packages/hydrogen/src/utilities/apiRoutes.ts +++ b/packages/hydrogen/src/utilities/apiRoutes.ts @@ -19,6 +19,8 @@ import type { import {emptySessionImplementation} from '../foundation/session/session.js'; import {UseShopQueryResponse} from '../hooks/useShopQuery/hooks.js'; import {FORM_REDIRECT_COOKIE, RSC_PATHNAME} from '../constants.js'; +import {TypedDocumentNode} from '@graphql-typed-document-node/core'; +import {print} from 'graphql'; let memoizedApiRoutes: Array = []; let memoizedRawRoutes: ImportGlobEagerOutput = {}; @@ -27,7 +29,9 @@ type RouteParams = Record; export type RequestOptions = { log: Logger; params: RouteParams; - queryShop: (args: QueryShopArgs) => Promise>; + queryShop: = {}>( + args: QueryShopArgs + ) => Promise>; session: SessionApi | null; hydrogenConfig: ResolvedHydrogenConfig; }; @@ -144,23 +148,23 @@ export function getApiRouteFromURL( * It's similar to the `useShopQuery` hook, which is available in server components. * To use `queryShop`, pass `shopifyConfig` to `renderHydrogen` inside `App.server.jsx`. */ -interface QueryShopArgs { +interface QueryShopArgs> { /** A string of the GraphQL query. * If no query is provided, then the `useShopQuery` makes no calls to the Storefront API. */ - query: string; + query: string | TypedDocumentNode; /** An object of the variables for the GraphQL query. */ - variables?: Record; + variables?: Variables; } function queryShopBuilder( shopifyConfigGetter: ResolvedHydrogenConfig['shopify'], request: HydrogenRequest ) { - return async function queryShop({ + return async function queryShop>({ query, variables, - }: QueryShopArgs): Promise { + }: QueryShopArgs): Promise> { const shopifyConfig = typeof shopifyConfigGetter === 'function' ? await shopifyConfigGetter(request) @@ -188,11 +192,14 @@ function queryShopBuilder( storefrontId, }); - const fetcher = fetchBuilder( + const fetcher = fetchBuilder>( `https://${storeDomain}/api/${storefrontApiVersion}/graphql.json`, { method: 'POST', - body: graphqlRequestBody(query, variables), + body: graphqlRequestBody( + typeof query === 'string' ? query : print(query), + variables + ), headers: { 'Content-Type': 'application/json', ...extraHeaders,