@shopify/hydrogen 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
  2. package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.js +1 -1
  3. package/dist/esnext/components/LocalizationProvider/index.d.ts +1 -0
  4. package/dist/esnext/components/LocalizationProvider/index.js +1 -0
  5. package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -3
  6. package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -3
  7. package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +1 -2
  8. package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -2
  9. package/dist/esnext/components/index.d.ts +1 -0
  10. package/dist/esnext/components/index.js +1 -0
  11. package/dist/esnext/entry-client.js +4 -6
  12. package/dist/esnext/entry-server.js +7 -14
  13. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.d.ts +2 -0
  14. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.js +4 -0
  15. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.d.ts +2 -0
  16. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.js +5 -0
  17. package/dist/esnext/foundation/RenderCacheProvider/hook.d.ts +11 -0
  18. package/dist/esnext/foundation/RenderCacheProvider/hook.js +34 -0
  19. package/dist/esnext/foundation/RenderCacheProvider/index.d.ts +1 -0
  20. package/dist/esnext/foundation/RenderCacheProvider/index.js +1 -0
  21. package/dist/esnext/foundation/RenderCacheProvider/types.d.ts +11 -0
  22. package/dist/esnext/foundation/RenderCacheProvider/types.js +1 -0
  23. package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.d.ts +1 -3
  24. package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.js +2 -4
  25. package/dist/esnext/foundation/ShopifyProvider/types.d.ts +0 -5
  26. package/dist/esnext/foundation/useQuery/hooks.d.ts +8 -6
  27. package/dist/esnext/foundation/useQuery/hooks.js +9 -11
  28. package/dist/esnext/foundation/useQuery/index.d.ts +0 -1
  29. package/dist/esnext/foundation/useQuery/index.js +0 -1
  30. package/dist/esnext/framework/cache.d.ts +2 -2
  31. package/dist/esnext/framework/cache.js +1 -1
  32. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +11 -0
  33. package/dist/esnext/framework/plugins/vite-plugin-react-server-components-shim.js +1 -13
  34. package/dist/esnext/handle-event.d.ts +1 -1
  35. package/dist/esnext/hooks/index.d.ts +1 -1
  36. package/dist/esnext/hooks/index.js +1 -1
  37. package/dist/esnext/hooks/useShopQuery/hooks.js +20 -14
  38. package/dist/esnext/types.d.ts +2 -1
  39. package/dist/esnext/utilities/suspense.d.ts +2 -2
  40. package/dist/esnext/utilities/suspense.js +0 -6
  41. package/dist/esnext/version.d.ts +1 -1
  42. package/dist/esnext/version.js +1 -1
  43. package/dist/node/framework/cache.d.ts +2 -2
  44. package/dist/node/framework/cache.js +2 -1
  45. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +11 -0
  46. package/dist/node/framework/plugins/vite-plugin-react-server-components-shim.js +1 -13
  47. package/dist/node/handle-event.d.ts +1 -1
  48. package/dist/node/types.d.ts +2 -1
  49. package/dist/node/utilities/suspense.d.ts +2 -2
  50. package/dist/node/utilities/suspense.js +0 -6
  51. package/dist/node/version.d.ts +1 -1
  52. package/dist/node/version.js +1 -1
  53. package/dist/worker/framework/cache.d.ts +2 -2
  54. package/dist/worker/framework/cache.js +1 -1
  55. package/dist/worker/handle-event.d.ts +1 -1
  56. package/dist/worker/types.d.ts +2 -1
  57. package/package.json +5 -5
  58. package/dist/esnext/foundation/useQuery/QueryProvider.d.ts +0 -6
  59. package/dist/esnext/foundation/useQuery/QueryProvider.js +0 -13
@@ -7,7 +7,7 @@ export interface CartEstimatedCostProps {
7
7
  children?: React.ReactNode;
8
8
  }
9
9
  /**
10
- * The [CartEstimatedCost](/api/storefront/reference/cart/cartestimatedcost) component renders a `Money` component with the
10
+ * The `CartEstimatedCost` component renders a `Money` component with the
11
11
  * cost associated with the `amountType` prop. If no `amountType` prop is specified, then it defaults to `totalAmount`.
12
12
  * If `children` is a function, then it will pass down the render props provided by the parent component.
13
13
  */
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { useCart } from '../CartProvider';
3
3
  import { Money } from '../Money';
4
4
  /**
5
- * The [CartEstimatedCost](/api/storefront/reference/cart/cartestimatedcost) component renders a `Money` component with the
5
+ * The `CartEstimatedCost` component renders a `Money` component with the
6
6
  * cost associated with the `amountType` prop. If no `amountType` prop is specified, then it defaults to `totalAmount`.
7
7
  * If `children` is a function, then it will pass down the render props provided by the parent component.
8
8
  */
@@ -1,2 +1,3 @@
1
+ export { LocalizationProvider } from './LocalizationProvider.server';
1
2
  export { useCountry } from '../../hooks/useCountry/useCountry';
2
3
  export { useAvailableCountries } from '../../hooks/useAvailableCountries/useAvailableCountries';
@@ -1,2 +1,3 @@
1
+ export { LocalizationProvider } from './LocalizationProvider.server';
1
2
  export { useCountry } from '../../hooks/useCountry/useCountry';
2
3
  export { useAvailableCountries } from '../../hooks/useAvailableCountries/useAvailableCountries';
@@ -8,8 +8,6 @@ export interface ProductPriceProps {
8
8
  }
9
9
  /**
10
10
  * The `ProductPrice` component renders a `Money` component with the product
11
- * [`priceRange`](/api/storefront/reference/products/productpricerange)'s `maxVariantPrice`
12
- * or `minVariantPrice`, for either the regular price or compare at price range.
13
- * It must be a descendent of the `ProductProvider` component.
11
+ * [`priceRange`](/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range. It must be a descendent of the `ProductProvider` component.
14
12
  */
15
13
  export declare function ProductPrice<TTag extends ElementType>(props: Props<TTag> & ProductPriceProps): JSX.Element | null;
@@ -3,9 +3,7 @@ import { Money } from '../Money';
3
3
  import { useProduct } from '../ProductProvider';
4
4
  /**
5
5
  * The `ProductPrice` component renders a `Money` component with the product
6
- * [`priceRange`](/api/storefront/reference/products/productpricerange)'s `maxVariantPrice`
7
- * or `minVariantPrice`, for either the regular price or compare at price range.
8
- * It must be a descendent of the `ProductProvider` component.
6
+ * [`priceRange`](/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range. It must be a descendent of the `ProductProvider` component.
9
7
  */
10
8
  export function ProductPrice(props) {
11
9
  var _a, _b, _c, _d;
@@ -13,8 +13,7 @@ export interface UnitPriceProps {
13
13
  }
14
14
  /**
15
15
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
16
- * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from
17
- * the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
16
+ * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
18
17
  *
19
18
  * If `children` is a function, then it will provide render props for the `children` corresponding to the object
20
19
  * returned by the `useMoney` hook and the `UnitPriceMeasurement` object.
@@ -4,8 +4,7 @@ import { Money } from '../Money';
4
4
  import { UnitPriceFragment as Fragment } from '../../graphql/graphql-constants';
5
5
  /**
6
6
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
7
- * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from
8
- * the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
7
+ * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
9
8
  *
10
9
  * If `children` is a function, then it will provide render props for the `children` corresponding to the object
11
10
  * returned by the `useMoney` hook and the `UnitPriceMeasurement` object.
@@ -28,6 +28,7 @@ export { CartLines } from './CartLines';
28
28
  export { CartCheckoutButton } from './CartCheckoutButton';
29
29
  export { CartShopPayButton } from './CartShopPayButton';
30
30
  export { CartEstimatedCost } from './CartEstimatedCost';
31
+ export { CartLineSelectedOptions } from './CartLineSelectedOptions';
31
32
  export { CartProvider, useCart, useCartAttributesUpdateCallback, useCartBuyerIdentityUpdateCallback, useCartNoteUpdateCallback, useCartCheckoutUrl, useCartCreateCallback, useCartDiscountCodesUpdateCallback, useCartFetch, useCartLinesAddCallback, useCartLinesRemoveCallback, useCartLinesTotalQuantity, useCartLinesUpdateCallback, useInstantCheckout, } from './CartProvider';
32
33
  export type { State, Status, Cart, CartWithActions, CartAction, } from './CartProvider';
33
34
  export { ProductProvider, useProduct, ProductProviderFragment, } from './ProductProvider';
@@ -19,6 +19,7 @@ export { CartLines } from './CartLines';
19
19
  export { CartCheckoutButton } from './CartCheckoutButton';
20
20
  export { CartShopPayButton } from './CartShopPayButton';
21
21
  export { CartEstimatedCost } from './CartEstimatedCost';
22
+ export { CartLineSelectedOptions } from './CartLineSelectedOptions';
22
23
  export { CartProvider, useCart, useCartAttributesUpdateCallback, useCartBuyerIdentityUpdateCallback, useCartNoteUpdateCallback, useCartCheckoutUrl, useCartCreateCallback, useCartDiscountCodesUpdateCallback, useCartFetch, useCartLinesAddCallback, useCartLinesRemoveCallback, useCartLinesTotalQuantity, useCartLinesUpdateCallback, useInstantCheckout, } from './CartProvider';
23
24
  export { ProductProvider, useProduct, ProductProviderFragment, } from './ProductProvider';
24
25
  export { ProductDescription } from './ProductDescription';
@@ -6,7 +6,6 @@ import { ErrorBoundary } from 'react-error-boundary';
6
6
  import { HelmetProvider } from 'react-helmet-async';
7
7
  import { useServerResponse } from './framework/Hydration/Cache.client';
8
8
  import { ServerStateProvider, ServerStateRouter } from './client';
9
- import { QueryProvider } from './hooks';
10
9
  const renderHydrogen = async (ClientWrapper) => {
11
10
  const root = document.getElementById('root');
12
11
  if (!root) {
@@ -25,11 +24,10 @@ function Content({ clientWrapper: ClientWrapper }) {
25
24
  });
26
25
  const response = useServerResponse(serverState);
27
26
  return (React.createElement(ServerStateProvider, { serverState: serverState, setServerState: setServerState },
28
- React.createElement(QueryProvider, null,
29
- React.createElement(HelmetProvider, null,
30
- React.createElement(BrowserRouter, null,
31
- React.createElement(ServerStateRouter, null),
32
- React.createElement(ClientWrapper, null, response.read()))))));
27
+ React.createElement(HelmetProvider, null,
28
+ React.createElement(BrowserRouter, null,
29
+ React.createElement(ServerStateRouter, null),
30
+ React.createElement(ClientWrapper, null, response.read())))));
33
31
  }
34
32
  function Error({ error }) {
35
33
  return (React.createElement("div", { style: { padding: '1em' } },
@@ -12,8 +12,8 @@ import { HelmetProvider } from 'react-helmet-async';
12
12
  import { Html } from './framework/Hydration/Html';
13
13
  import { HydrationWriter } from './framework/Hydration/writer.server';
14
14
  import { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
15
- import { dehydrate } from 'react-query/hydration';
16
15
  import { getCacheControlHeader } from './framework/cache';
16
+ import { RenderCacheProvider } from './foundation/RenderCacheProvider';
17
17
  /**
18
18
  * react-dom/unstable-fizz provides different entrypoints based on runtime:
19
19
  * - `renderToReadableStream` for "browser" (aka worker)
@@ -173,9 +173,11 @@ const renderHydrogen = (App, hook) => {
173
173
  function buildReactApp({ App, state, context, request, dev, }) {
174
174
  const helmetContext = {};
175
175
  const componentResponse = new ServerComponentResponse();
176
- const ReactApp = (props) => (React.createElement(StaticRouter, { location: { pathname: state.pathname, search: state.search }, context: context },
177
- React.createElement(HelmetProvider, { context: helmetContext },
178
- React.createElement(App, { ...props, request: request, response: componentResponse }))));
176
+ const renderCache = {};
177
+ const ReactApp = (props) => (React.createElement(RenderCacheProvider, { cache: renderCache },
178
+ React.createElement(StaticRouter, { location: { pathname: state.pathname, search: state.search }, context: context },
179
+ React.createElement(HelmetProvider, { context: helmetContext },
180
+ React.createElement(App, { ...props, request: request, response: componentResponse })))));
179
181
  return { helmetContext, ReactApp, componentResponse };
180
182
  }
181
183
  function extractHeadElements(helmetContext) {
@@ -287,18 +289,9 @@ function renderAppFromBufferedStream(app, isReactHydrationRequest) {
287
289
  * the results in a context object, and re-render.
288
290
  */
289
291
  async function renderAppFromStringWithPrepass(ReactApp, state, isReactHydrationRequest) {
290
- const hydrationContext = {};
291
292
  const app = isReactHydrationRequest ? (React.createElement(HydrationContext.Provider, { value: true },
292
- React.createElement(ReactApp, { hydrationContext: hydrationContext, ...state }))) : (React.createElement(ReactApp, { hydrationContext: hydrationContext, ...state }));
293
+ React.createElement(ReactApp, { ...state }))) : (React.createElement(ReactApp, { ...state }));
293
294
  await ssrPrepass(app);
294
- /**
295
- * Dehydrate all the queries made during the prepass above and store
296
- * them in the context object to be used for the next render pass.
297
- * This prevents rendering the Suspense fallback in `renderToString`.
298
- */
299
- if (hydrationContext.queryClient) {
300
- hydrationContext.dehydratedState = dehydrate(hydrationContext.queryClient);
301
- }
302
295
  const body = renderToString(app);
303
296
  return isReactHydrationRequest
304
297
  ? generateWireSyntaxFromRenderedHtml(body)
@@ -0,0 +1,2 @@
1
+ import type { RenderCacheProviderProps } from './types';
2
+ export declare const RenderCacheContext: import("react").Context<RenderCacheProviderProps>;
@@ -0,0 +1,4 @@
1
+ import { createContext } from 'react';
2
+ export const RenderCacheContext = createContext({
3
+ cache: {},
4
+ });
@@ -0,0 +1,2 @@
1
+ import type { RenderCacheProviderProps } from './types';
2
+ export declare function RenderCacheProvider({ cache, children, }: RenderCacheProviderProps): JSX.Element;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { RenderCacheContext } from './RenderCacheContext';
3
+ export function RenderCacheProvider({ cache, children, }) {
4
+ return (React.createElement(RenderCacheContext.Provider, { value: { cache } }, children));
5
+ }
@@ -0,0 +1,11 @@
1
+ import type { QueryKey } from '../../types';
2
+ import type { RenderCacheProviderProps, RenderCacheResult } from './types';
3
+ /**
4
+ * Returns the unique identifier for the current rendering request
5
+ */
6
+ export declare function useRenderCache(): RenderCacheProviderProps;
7
+ /**
8
+ * Returns data stored in the render cache
9
+ * It will throw the promise if data is not ready
10
+ */
11
+ export declare function useRenderCacheData<T>(key: QueryKey, fetcher: () => Promise<T>): RenderCacheResult<T>;
@@ -0,0 +1,34 @@
1
+ import { useContext } from 'react';
2
+ import { RenderCacheContext } from './RenderCacheContext';
3
+ import { hashKey } from '../../framework/cache';
4
+ /**
5
+ * Returns the unique identifier for the current rendering request
6
+ */
7
+ export function useRenderCache() {
8
+ const context = useContext(RenderCacheContext);
9
+ if (!context) {
10
+ throw new Error('No RenderCache Context found');
11
+ }
12
+ return context;
13
+ }
14
+ /**
15
+ * Returns data stored in the render cache
16
+ * It will throw the promise if data is not ready
17
+ */
18
+ export function useRenderCacheData(key, fetcher) {
19
+ const cacheKey = hashKey(key);
20
+ const { cache } = useRenderCache();
21
+ if (!cache[cacheKey]) {
22
+ let data;
23
+ let promise;
24
+ cache[cacheKey] = () => {
25
+ if (data !== undefined)
26
+ return data;
27
+ if (!promise) {
28
+ promise = fetcher().then((r) => (data = { data: r }), (e) => (data = { data: e }));
29
+ }
30
+ throw promise;
31
+ };
32
+ }
33
+ return cache[cacheKey]();
34
+ }
@@ -0,0 +1 @@
1
+ export { RenderCacheProvider } from './RenderCacheProvider';
@@ -0,0 +1 @@
1
+ export { RenderCacheProvider } from './RenderCacheProvider';
@@ -0,0 +1,11 @@
1
+ export declare type RenderCache = {
2
+ [key: string]: () => unknown;
3
+ };
4
+ export declare type RenderCacheProviderProps = {
5
+ /** A cache to hold all queries performed within a render request */
6
+ cache: RenderCache;
7
+ children?: React.ReactNode;
8
+ };
9
+ export interface RenderCacheResult<T> {
10
+ data: T;
11
+ }
@@ -1,8 +1,6 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { ShopifyConfig } from '../../types';
3
- import { ReactQueryHydrationContext } from './types';
4
- export declare function ShopifyServerProvider({ children, shopifyConfig, hydrationContext, }: {
3
+ export declare function ShopifyServerProvider({ children, shopifyConfig, }: {
5
4
  children: ReactElement;
6
5
  shopifyConfig: ShopifyConfig;
7
- hydrationContext: ReactQueryHydrationContext;
8
6
  }): JSX.Element;
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
2
  import { ShopifyProvider } from './ShopifyProvider';
3
- import { QueryProvider } from '../../foundation/useQuery';
4
- export function ShopifyServerProvider({ children, shopifyConfig, hydrationContext, }) {
5
- return (React.createElement(ShopifyProvider, { shopifyConfig: shopifyConfig },
6
- React.createElement(QueryProvider, { hydrationContext: hydrationContext }, children)));
3
+ export function ShopifyServerProvider({ children, shopifyConfig, }) {
4
+ return (React.createElement(ShopifyProvider, { shopifyConfig: shopifyConfig }, children));
7
5
  }
@@ -1,4 +1,3 @@
1
- import type { QueryClient } from 'react-query';
2
1
  import { ShopifyConfig } from '../../types';
3
2
  export declare type ShopifyProviderValue = ShopifyConfig;
4
3
  export declare type ShopifyProviderProps = {
@@ -8,7 +7,3 @@ export declare type ShopifyProviderProps = {
8
7
  children?: React.ReactNode;
9
8
  manager?: any;
10
9
  };
11
- export interface ReactQueryHydrationContext {
12
- queryClient?: QueryClient;
13
- dehydratedState?: any;
14
- }
@@ -1,15 +1,17 @@
1
- import type { UseQueryOptions, QueryKey, QueryFunction } from 'react-query';
2
- import { CacheOptions } from '../../types';
3
- export interface HydrogenUseQueryOptions<TQueryFnData = unknown, TError = unknown, TData = TQueryFnData, TQueryKey extends QueryKey = QueryKey> extends UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
1
+ import type { CacheOptions, QueryKey } from '../../types';
2
+ import type { RenderCacheResult } from '../RenderCacheProvider/types';
3
+ export interface HydrogenUseQueryOptions {
4
4
  cache: CacheOptions;
5
5
  }
6
6
  /**
7
- * The `useQuery` hook is a wrapper around `useQuery` from `react-query`. It supports Suspense calls on the server and on the client.
7
+ * The `useQuery` hook is a wrapper around Suspense calls and
8
+ * global runtime's Cache if it exist.
9
+ * It supports Suspense calls on the server and on the client.
8
10
  */
9
11
  export declare function useQuery<T>(
10
12
  /** A string or array to uniquely identify the current query. */
11
13
  key: QueryKey,
12
14
  /** An asynchronous query function like `fetch` which returns data. */
13
- queryFn: QueryFunction<T>,
15
+ queryFn: () => Promise<T>,
14
16
  /** Options including `cache` to manage the cache behavior of the sub-request. */
15
- queryOptions?: HydrogenUseQueryOptions<T, Error, T, QueryKey>): import("react-query").UseQueryResult<T, Error>;
17
+ queryOptions?: HydrogenUseQueryOptions): RenderCacheResult<T>;
@@ -1,8 +1,10 @@
1
- import { useQuery as useReactQuery } from 'react-query';
2
1
  import { deleteItemFromCache, getItemFromCache, isStale, setItemInCache, } from '../../framework/cache';
3
2
  import { runDelayedFunction } from '../../framework/runtime';
3
+ import { useRenderCacheData } from '../RenderCacheProvider/hook';
4
4
  /**
5
- * The `useQuery` hook is a wrapper around `useQuery` from `react-query`. It supports Suspense calls on the server and on the client.
5
+ * The `useQuery` hook is a wrapper around Suspense calls and
6
+ * global runtime's Cache if it exist.
7
+ * It supports Suspense calls on the server and on the client.
6
8
  */
7
9
  export function useQuery(
8
10
  /** A string or array to uniquely identify the current query. */
@@ -11,14 +13,10 @@ key,
11
13
  queryFn,
12
14
  /** Options including `cache` to manage the cache behavior of the sub-request. */
13
15
  queryOptions) {
16
+ return useRenderCacheData(key, cachedQueryFnBuilder(key, queryFn, queryOptions));
17
+ }
18
+ function cachedQueryFnBuilder(key, queryFn, queryOptions) {
14
19
  const resolvedQueryOptions = {
15
- /**
16
- * Prevent react-query from from retrying request failures. This sometimes bites developers
17
- * because they will get back a 200 GraphQL response with errors, but not properly check
18
- * for errors. This leads to a failed `queryFn` and react-query keeps running it, leading
19
- * to a much slower response time and a poor developer experience.
20
- */
21
- retry: false,
22
20
  ...(queryOptions !== null && queryOptions !== void 0 ? queryOptions : {}),
23
21
  };
24
22
  /**
@@ -27,7 +25,7 @@ queryOptions) {
27
25
  async function cachedQueryFn() {
28
26
  const cacheResponse = await getItemFromCache(key);
29
27
  async function generateNewOutput() {
30
- return await queryFn({});
28
+ return await queryFn();
31
29
  }
32
30
  if (cacheResponse) {
33
31
  const [output, response] = cacheResponse;
@@ -64,5 +62,5 @@ queryOptions) {
64
62
  runDelayedFunction(async () => await setItemInCache(key, newOutput, resolvedQueryOptions === null || resolvedQueryOptions === void 0 ? void 0 : resolvedQueryOptions.cache));
65
63
  return newOutput;
66
64
  }
67
- return useReactQuery(key, cachedQueryFn, resolvedQueryOptions);
65
+ return cachedQueryFn;
68
66
  }
@@ -1,2 +1 @@
1
1
  export { useQuery } from './hooks';
2
- export { QueryProvider } from './QueryProvider';
@@ -1,2 +1 @@
1
1
  export { useQuery } from './hooks';
2
- export { QueryProvider } from './QueryProvider';
@@ -1,5 +1,4 @@
1
- import type { QueryKey } from 'react-query';
2
- import type { CacheOptions } from '../types';
1
+ import type { CacheOptions, QueryKey } from '../types';
3
2
  export declare function generateCacheControlHeader(options: CacheOptions): string;
4
3
  /**
5
4
  * Use a preview header during development.
@@ -9,6 +8,7 @@ export declare function generateCacheControlHeader(options: CacheOptions): strin
9
8
  export declare function getCacheControlHeader({ dev }: {
10
9
  dev?: boolean;
11
10
  }): "cache-control-preview" | "cache-control";
11
+ export declare function hashKey(key: QueryKey): string;
12
12
  /**
13
13
  * Get an item from the cache. If a match is found, returns a tuple
14
14
  * containing the `JSON.parse` version of the response as well
@@ -21,7 +21,7 @@ export function generateCacheControlHeader(options) {
21
21
  export function getCacheControlHeader({ dev }) {
22
22
  return dev ? 'cache-control-preview' : 'cache-control';
23
23
  }
24
- function hashKey(key) {
24
+ export function hashKey(key) {
25
25
  const rawKey = key instanceof Array ? key : [key];
26
26
  /**
27
27
  * TODO: Smarter hash
@@ -16,6 +16,17 @@ export default () => {
16
16
  },
17
17
  build: {
18
18
  sourcemap: true,
19
+ /**
20
+ * By default, SSR dedupe logic gets bundled which runs `require('module')`.
21
+ * We don't want this in our workers runtime, because `require` is not supported.
22
+ */
23
+ rollupOptions: process.env.WORKER
24
+ ? {
25
+ output: {
26
+ format: 'es',
27
+ },
28
+ }
29
+ : {},
19
30
  },
20
31
  ssr: {
21
32
  external: ['isomorphic-dompurify'],
@@ -72,19 +72,7 @@ export default () => {
72
72
  }
73
73
  },
74
74
  };
75
- // Mitigation for upcoming minor Vite update
76
- // https://github.com/vitejs/vite/pull/5253
77
- // TO-DO: When the vite package is updated with the above Vite PR,
78
- // clean up this function and treat `options` param as objects
79
- // from this point forward
80
- // Timeline: Targetting for Vite 2.7
81
75
  function isSSR(options) {
82
- if (typeof options === 'boolean') {
83
- return options;
84
- }
85
- if (typeof options === 'object') {
86
- return !!options.ssr;
87
- }
88
- return false;
76
+ return !!(options === null || options === void 0 ? void 0 : options.ssr);
89
77
  }
90
78
  };
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
4
4
  import { RuntimeContext } from './framework/runtime';
5
5
  interface HydrogenFetchEvent {
@@ -1,6 +1,6 @@
1
1
  export { useProductOptions } from './useProductOptions';
2
2
  export * from './useProductOptions/types';
3
- export { useQuery, QueryProvider } from '../foundation/useQuery';
3
+ export { useQuery } from '../foundation/useQuery';
4
4
  export { useMoney } from './useMoney';
5
5
  export { useMeasurement } from './useMeasurement';
6
6
  export { useParsedMetafields } from './useParsedMetafields';
@@ -1,6 +1,6 @@
1
1
  export { useProductOptions } from './useProductOptions';
2
2
  export * from './useProductOptions/types';
3
- export { useQuery, QueryProvider } from '../foundation/useQuery';
3
+ export { useQuery } from '../foundation/useQuery';
4
4
  export { useMoney } from './useMoney';
5
5
  export { useMeasurement } from './useMeasurement';
6
6
  export { useParsedMetafields } from './useParsedMetafields';
@@ -11,21 +11,12 @@ export function useShopQuery({ query, variables = {}, cache = {}, }) {
11
11
  if (isClient()) {
12
12
  throw new Error('Shopify Storefront API requests should only be made from the server.');
13
13
  }
14
- const { storeDomain, storefrontToken, graphqlApiVersion } = useShop();
15
- const body = query ? graphqlRequestBody(query, variables) : "";
16
- const url = `https://${storeDomain}/api/${graphqlApiVersion}/graphql.json`;
17
- const request = new Request(url, {
18
- method: 'POST',
19
- headers: {
20
- 'X-Shopify-Storefront-Access-Token': storefrontToken,
21
- 'content-type': 'application/json',
22
- },
23
- body,
24
- });
25
- const { data } = useQuery([storeDomain, graphqlApiVersion, body], query
14
+ const body = query ? graphqlRequestBody(query, variables) : '';
15
+ const { request, key } = createShopRequest(body);
16
+ const { data } = useQuery(key, query
26
17
  ? fetchBuilder(request)
27
- // If no query, avoid calling SFAPI & return nothing
28
- : async () => ({ data: undefined, errors: undefined }), { cache });
18
+ : // If no query, avoid calling SFAPI & return nothing
19
+ async () => ({ data: undefined, errors: undefined }), { cache });
29
20
  /**
30
21
  * GraphQL errors get printed to the console but ultimately
31
22
  * get returned to the consumer.
@@ -42,3 +33,18 @@ export function useShopQuery({ query, variables = {}, cache = {}, }) {
42
33
  }
43
34
  return data;
44
35
  }
36
+ function createShopRequest(body) {
37
+ const { storeDomain, storefrontToken, graphqlApiVersion } = useShop();
38
+ const url = `https://${storeDomain}/api/${graphqlApiVersion}/graphql.json`;
39
+ return {
40
+ request: new Request(url, {
41
+ method: 'POST',
42
+ headers: {
43
+ 'X-Shopify-Storefront-Access-Token': storefrontToken,
44
+ 'content-type': 'application/json',
45
+ },
46
+ body,
47
+ }),
48
+ key: [storeDomain, graphqlApiVersion, body],
49
+ };
50
+ }
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
4
4
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
5
5
  import type { Metafield, Image, MediaContentType } from './graphql/types/types';
@@ -78,6 +78,7 @@ export interface Measurement {
78
78
  unit: string;
79
79
  value: number;
80
80
  }
81
+ export declare type QueryKey = string | readonly unknown[];
81
82
  export interface CacheOptions {
82
83
  private?: boolean;
83
84
  maxAge?: number;
@@ -2,6 +2,6 @@
2
2
  * Wrap the fetch promise in a way that React Suspense understands.
3
3
  * Essentially, keep throwing something until you have legit data.
4
4
  */
5
- export declare function wrapPromise(promise: Promise<any>): {
6
- read: () => any;
5
+ export declare function wrapPromise<T>(promise: Promise<T>): {
6
+ read: () => T;
7
7
  };
@@ -11,14 +11,8 @@ export function wrapPromise(promise) {
11
11
  }, (err) => {
12
12
  status = 'error';
13
13
  response = err;
14
- throw err;
15
14
  });
16
15
  const read = () => {
17
- /**
18
- * TODO: This logic doesn't hold up when an error is thrown. For some reason.
19
- * We instead throw the exception above in the suspender. We should revisit
20
- * this and add a better server fetch implementation.
21
- */
22
16
  switch (status) {
23
17
  case 'pending':
24
18
  throw suspender;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "0.7.1";
1
+ export declare const LIB_VERSION = "0.8.0";
@@ -1 +1 @@
1
- export const LIB_VERSION = '0.7.1';
1
+ export const LIB_VERSION = '0.8.0';
@@ -1,5 +1,4 @@
1
- import type { QueryKey } from 'react-query';
2
- import type { CacheOptions } from '../types';
1
+ import type { CacheOptions, QueryKey } from '../types';
3
2
  export declare function generateCacheControlHeader(options: CacheOptions): string;
4
3
  /**
5
4
  * Use a preview header during development.
@@ -9,6 +8,7 @@ export declare function generateCacheControlHeader(options: CacheOptions): strin
9
8
  export declare function getCacheControlHeader({ dev }: {
10
9
  dev?: boolean;
11
10
  }): "cache-control-preview" | "cache-control";
11
+ export declare function hashKey(key: QueryKey): string;
12
12
  /**
13
13
  * Get an item from the cache. If a match is found, returns a tuple
14
14
  * containing the `JSON.parse` version of the response as well
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isStale = exports.deleteItemFromCache = exports.setItemInCache = exports.getItemFromCache = exports.getCacheControlHeader = exports.generateCacheControlHeader = void 0;
3
+ exports.isStale = exports.deleteItemFromCache = exports.setItemInCache = exports.getItemFromCache = exports.hashKey = exports.getCacheControlHeader = exports.generateCacheControlHeader = void 0;
4
4
  const runtime_1 = require("./runtime");
5
5
  const DEFAULT_SUBREQUEST_CACHE_OPTIONS = {
6
6
  maxAge: 1,
@@ -33,6 +33,7 @@ function hashKey(key) {
33
33
  */
34
34
  return rawKey.map((k) => JSON.stringify(k)).join('');
35
35
  }
36
+ exports.hashKey = hashKey;
36
37
  /**
37
38
  * Cache API is weird. We just need a full URL, so we make one up.
38
39
  */
@@ -18,6 +18,17 @@ exports.default = () => {
18
18
  },
19
19
  build: {
20
20
  sourcemap: true,
21
+ /**
22
+ * By default, SSR dedupe logic gets bundled which runs `require('module')`.
23
+ * We don't want this in our workers runtime, because `require` is not supported.
24
+ */
25
+ rollupOptions: process.env.WORKER
26
+ ? {
27
+ output: {
28
+ format: 'es',
29
+ },
30
+ }
31
+ : {},
21
32
  },
22
33
  ssr: {
23
34
  external: ['isomorphic-dompurify'],
@@ -77,19 +77,7 @@ exports.default = () => {
77
77
  }
78
78
  },
79
79
  };
80
- // Mitigation for upcoming minor Vite update
81
- // https://github.com/vitejs/vite/pull/5253
82
- // TO-DO: When the vite package is updated with the above Vite PR,
83
- // clean up this function and treat `options` param as objects
84
- // from this point forward
85
- // Timeline: Targetting for Vite 2.7
86
80
  function isSSR(options) {
87
- if (typeof options === 'boolean') {
88
- return options;
89
- }
90
- if (typeof options === 'object') {
91
- return !!options.ssr;
92
- }
93
- return false;
81
+ return !!(options === null || options === void 0 ? void 0 : options.ssr);
94
82
  }
95
83
  };
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
4
4
  import { RuntimeContext } from './framework/runtime';
5
5
  interface HydrogenFetchEvent {
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
4
4
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
5
5
  import type { Metafield, Image, MediaContentType } from './graphql/types/types';
@@ -78,6 +78,7 @@ export interface Measurement {
78
78
  unit: string;
79
79
  value: number;
80
80
  }
81
+ export declare type QueryKey = string | readonly unknown[];
81
82
  export interface CacheOptions {
82
83
  private?: boolean;
83
84
  maxAge?: number;
@@ -2,6 +2,6 @@
2
2
  * Wrap the fetch promise in a way that React Suspense understands.
3
3
  * Essentially, keep throwing something until you have legit data.
4
4
  */
5
- export declare function wrapPromise(promise: Promise<any>): {
6
- read: () => any;
5
+ export declare function wrapPromise<T>(promise: Promise<T>): {
6
+ read: () => T;
7
7
  };
@@ -14,14 +14,8 @@ function wrapPromise(promise) {
14
14
  }, (err) => {
15
15
  status = 'error';
16
16
  response = err;
17
- throw err;
18
17
  });
19
18
  const read = () => {
20
- /**
21
- * TODO: This logic doesn't hold up when an error is thrown. For some reason.
22
- * We instead throw the exception above in the suspender. We should revisit
23
- * this and add a better server fetch implementation.
24
- */
25
19
  switch (status) {
26
20
  case 'pending':
27
21
  throw suspender;
@@ -1 +1 @@
1
- export declare const LIB_VERSION = "0.7.1";
1
+ export declare const LIB_VERSION = "0.8.0";
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LIB_VERSION = void 0;
4
- exports.LIB_VERSION = '0.7.1';
4
+ exports.LIB_VERSION = '0.8.0';
@@ -1,5 +1,4 @@
1
- import type { QueryKey } from 'react-query';
2
- import type { CacheOptions } from '../types';
1
+ import type { CacheOptions, QueryKey } from '../types';
3
2
  export declare function generateCacheControlHeader(options: CacheOptions): string;
4
3
  /**
5
4
  * Use a preview header during development.
@@ -9,6 +8,7 @@ export declare function generateCacheControlHeader(options: CacheOptions): strin
9
8
  export declare function getCacheControlHeader({ dev }: {
10
9
  dev?: boolean;
11
10
  }): "cache-control-preview" | "cache-control";
11
+ export declare function hashKey(key: QueryKey): string;
12
12
  /**
13
13
  * Get an item from the cache. If a match is found, returns a tuple
14
14
  * containing the `JSON.parse` version of the response as well
@@ -21,7 +21,7 @@ export function generateCacheControlHeader(options) {
21
21
  export function getCacheControlHeader({ dev }) {
22
22
  return dev ? 'cache-control-preview' : 'cache-control';
23
23
  }
24
- function hashKey(key) {
24
+ export function hashKey(key) {
25
25
  const rawKey = key instanceof Array ? key : [key];
26
26
  /**
27
27
  * TODO: Smarter hash
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@types/node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
4
4
  import { RuntimeContext } from './framework/runtime';
5
5
  interface HydrogenFetchEvent {
@@ -1,5 +1,5 @@
1
1
  /// <reference types="@types/node" />
2
- import type { ServerResponse } from 'http';
2
+ import { ServerResponse } from 'http';
3
3
  import type { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
4
4
  import type { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
5
5
  import type { Metafield, Image, MediaContentType } from './graphql/types/types';
@@ -78,6 +78,7 @@ export interface Measurement {
78
78
  unit: string;
79
79
  value: number;
80
80
  }
81
+ export declare type QueryKey = string | readonly unknown[];
81
82
  export interface CacheOptions {
82
83
  private?: boolean;
83
84
  maxAge?: number;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "@shopify:registry": "https://registry.npmjs.org"
6
6
  },
7
- "version": "0.7.1",
7
+ "version": "0.8.0",
8
8
  "description": "Modern custom Shopify storefronts",
9
9
  "license": "MIT",
10
10
  "main": "dist/esnext/index.js",
@@ -68,6 +68,7 @@
68
68
  "@types/react": "^17.0.3",
69
69
  "@types/react-dom": "^17.0.3",
70
70
  "@types/react-router-dom": "^5.1.7",
71
+ "@types/ws": "^8.2.0",
71
72
  "babel-loader": "^8.2.2",
72
73
  "cpy-cli": "3.1.1",
73
74
  "mkdirp": "^1.0.4",
@@ -80,10 +81,10 @@
80
81
  "react": "^18",
81
82
  "react-dom": "^18",
82
83
  "react-router-dom": "^5.2.0",
83
- "vite": "^2.6.14"
84
+ "vite": "^2.7.0"
84
85
  },
85
86
  "dependencies": {
86
- "@vitejs/plugin-react": "^1.1.0",
87
+ "@vitejs/plugin-react": "^1.1.1",
87
88
  "connect": "^3.7.0",
88
89
  "es-module-lexer": "^0.9.0",
89
90
  "fast-glob": "^3.2.5",
@@ -95,9 +96,8 @@
95
96
  "node-fetch": "^2.6.1",
96
97
  "react-error-boundary": "^3.1.3",
97
98
  "react-helmet-async": "^1.0.9",
98
- "react-query": "^3.18.1",
99
99
  "react-ssr-prepass": "^1.4.0",
100
100
  "vite-plugin-inspect": "^0.3.6"
101
101
  },
102
- "gitHead": "34baabab8643e8f0754844760de8a481c9d67971"
102
+ "gitHead": "c07762e2d18d0b0fc5ee76aa688752dcc29e7d07"
103
103
  }
@@ -1,6 +0,0 @@
1
- import { ReactNode } from 'react';
2
- import type { ReactQueryHydrationContext } from '../../foundation/ShopifyProvider/types';
3
- export declare function QueryProvider({ children, hydrationContext, }: {
4
- children: ReactNode;
5
- hydrationContext?: ReactQueryHydrationContext;
6
- }): JSX.Element;
@@ -1,13 +0,0 @@
1
- import React from 'react';
2
- import { QueryClientProvider, QueryClient } from 'react-query';
3
- import { Hydrate } from 'react-query/hydration';
4
- export function QueryProvider({ children, hydrationContext, }) {
5
- const queryClient = new QueryClient({
6
- defaultOptions: { queries: { suspense: true } },
7
- });
8
- if (hydrationContext) {
9
- hydrationContext.queryClient = queryClient;
10
- }
11
- return (React.createElement(QueryClientProvider, { client: queryClient },
12
- React.createElement(Hydrate, { state: hydrationContext === null || hydrationContext === void 0 ? void 0 : hydrationContext.dehydratedState }, children)));
13
- }