@shopify/hydrogen 0.6.3 → 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 (146) hide show
  1. package/dist/esnext/components/AddToCartButton/AddToCartButton.client.d.ts +1 -1
  2. package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +3 -3
  3. package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
  4. package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.js +1 -1
  5. package/dist/esnext/components/CartLineProvider/context.d.ts +3 -3
  6. package/dist/esnext/components/CartProvider/CartProvider.client.js +0 -1
  7. package/dist/esnext/components/ExternalVideo/ExternalVideo.d.ts +1 -1
  8. package/dist/esnext/components/Image/Image.d.ts +1 -1
  9. package/dist/esnext/components/LocalizationProvider/index.d.ts +1 -0
  10. package/dist/esnext/components/LocalizationProvider/index.js +1 -0
  11. package/dist/esnext/components/MediaFile/MediaFile.d.ts +1 -1
  12. package/dist/esnext/components/Metafield/Metafield.client.d.ts +1 -1
  13. package/dist/esnext/components/Metafield/Metafield.client.js +8 -0
  14. package/dist/esnext/components/Metafield/MetafieldFragment.d.ts +16 -1
  15. package/dist/esnext/components/Metafield/components/StarRating/StarRating.d.ts +1 -1
  16. package/dist/esnext/components/Metafield/index.d.ts +2 -2
  17. package/dist/esnext/components/Model3D/Model3D.client.d.ts +3 -1
  18. package/dist/esnext/components/Model3D/Model3D.client.js +1 -1
  19. package/dist/esnext/components/Money/Money.client.d.ts +1 -1
  20. package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -3
  21. package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -3
  22. package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +1 -1
  23. package/dist/esnext/components/ProductProvider/context.d.ts +2 -2
  24. package/dist/esnext/components/ProductProvider/types.d.ts +2 -2
  25. package/dist/esnext/components/SelectedVariantAddToCartButton/SelectedVariantAddToCartButton.client.d.ts +1 -1
  26. package/dist/esnext/components/SelectedVariantAddToCartButton/SelectedVariantAddToCartButton.client.js +1 -1
  27. package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +2 -3
  28. package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -2
  29. package/dist/esnext/components/Video/Video.d.ts +1 -1
  30. package/dist/esnext/components/index.d.ts +3 -2
  31. package/dist/esnext/components/index.js +1 -0
  32. package/dist/esnext/entry-client.js +4 -6
  33. package/dist/esnext/entry-server.js +49 -32
  34. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.d.ts +2 -0
  35. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.js +4 -0
  36. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.d.ts +2 -0
  37. package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.js +5 -0
  38. package/dist/esnext/foundation/RenderCacheProvider/hook.d.ts +11 -0
  39. package/dist/esnext/foundation/RenderCacheProvider/hook.js +34 -0
  40. package/dist/esnext/foundation/RenderCacheProvider/index.d.ts +1 -0
  41. package/dist/esnext/foundation/RenderCacheProvider/index.js +1 -0
  42. package/dist/esnext/foundation/RenderCacheProvider/types.d.ts +11 -0
  43. package/dist/esnext/foundation/RenderCacheProvider/types.js +1 -0
  44. package/dist/esnext/foundation/Router/ServerStateRouter.client.js +5 -3
  45. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.client.d.ts +19 -11
  46. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.client.js +21 -20
  47. package/dist/esnext/foundation/ServerStateProvider/index.d.ts +2 -1
  48. package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.d.ts +1 -3
  49. package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.js +2 -4
  50. package/dist/esnext/foundation/ShopifyProvider/types.d.ts +0 -5
  51. package/dist/esnext/foundation/useQuery/hooks.d.ts +17 -0
  52. package/dist/esnext/{hooks → foundation}/useQuery/hooks.js +14 -6
  53. package/dist/esnext/foundation/useQuery/index.d.ts +1 -0
  54. package/dist/esnext/foundation/useQuery/index.js +1 -0
  55. package/dist/esnext/foundation/useServerState/use-server-state.d.ts +2 -2
  56. package/dist/esnext/foundation/useServerState/use-server-state.js +1 -1
  57. package/dist/esnext/framework/ClientMarker/ClientMarker.js +0 -1
  58. package/dist/esnext/framework/Hydration/Cache.client.js +3 -1
  59. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
  60. package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +13 -0
  61. package/dist/esnext/framework/Hydration/wire.server.js +1 -1
  62. package/dist/esnext/framework/Hydration/writer.server.js +1 -0
  63. package/dist/esnext/framework/cache.d.ts +2 -2
  64. package/dist/esnext/framework/cache.js +1 -1
  65. package/dist/esnext/framework/middleware.d.ts +5 -1
  66. package/dist/esnext/framework/middleware.js +12 -8
  67. package/dist/esnext/framework/plugins/resolver.d.ts +1 -0
  68. package/dist/esnext/framework/plugins/resolver.js +3 -0
  69. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +15 -1
  70. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +8 -2
  71. package/dist/esnext/framework/plugins/vite-plugin-react-server-components-shim.js +10 -20
  72. package/dist/esnext/framework/server-components.js +25 -47
  73. package/dist/esnext/graphql/graphql-constants.d.ts +74 -37
  74. package/dist/esnext/graphql/graphql-constants.js +89 -15
  75. package/dist/esnext/handle-event.d.ts +1 -1
  76. package/dist/esnext/handle-event.js +8 -4
  77. package/dist/esnext/hooks/index.d.ts +1 -1
  78. package/dist/esnext/hooks/index.js +1 -1
  79. package/dist/esnext/hooks/useCartLine/useCartLine.d.ts +3 -3
  80. package/dist/esnext/hooks/useMoney/hooks.js +2 -16
  81. package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.d.ts +2 -3
  82. package/dist/esnext/hooks/useProductOptions/types.d.ts +2 -3
  83. package/dist/esnext/hooks/useShopQuery/hooks.d.ts +4 -2
  84. package/dist/esnext/hooks/useShopQuery/hooks.js +22 -13
  85. package/dist/esnext/types.d.ts +21 -4
  86. package/dist/esnext/utilities/flattenConnection/flattenConnection.d.ts +0 -7
  87. package/dist/esnext/utilities/flattenConnection/flattenConnection.js +0 -7
  88. package/dist/esnext/utilities/isClient/isClient.d.ts +0 -4
  89. package/dist/esnext/utilities/isClient/isClient.js +0 -4
  90. package/dist/esnext/utilities/isServer/isServer.d.ts +0 -4
  91. package/dist/esnext/utilities/isServer/isServer.js +0 -4
  92. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +2 -33
  93. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.js +0 -31
  94. package/dist/esnext/utilities/suspense.d.ts +2 -2
  95. package/dist/esnext/utilities/suspense.js +0 -6
  96. package/dist/esnext/version.d.ts +1 -1
  97. package/dist/esnext/version.js +1 -1
  98. package/dist/node/framework/ClientMarker/ClientMarker.js +2 -3
  99. package/dist/node/framework/Hydration/Cache.client.js +7 -5
  100. package/dist/node/framework/Hydration/HydrationContext.server.js +1 -1
  101. package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
  102. package/dist/node/framework/Hydration/ServerComponentResponse.server.js +15 -2
  103. package/dist/node/framework/Hydration/react-utils.js +3 -3
  104. package/dist/node/framework/Hydration/wire.server.js +2 -2
  105. package/dist/node/framework/Hydration/writer.server.js +1 -0
  106. package/dist/node/framework/cache.d.ts +2 -2
  107. package/dist/node/framework/cache.js +5 -4
  108. package/dist/node/framework/middleware.d.ts +5 -1
  109. package/dist/node/framework/middleware.js +17 -11
  110. package/dist/node/framework/plugin.js +5 -5
  111. package/dist/node/framework/plugins/resolver.d.ts +1 -0
  112. package/dist/node/framework/plugins/resolver.js +7 -0
  113. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +15 -1
  114. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +8 -2
  115. package/dist/node/framework/plugins/vite-plugin-react-server-components-shim.js +11 -21
  116. package/dist/node/framework/server-components.js +27 -49
  117. package/dist/node/handle-event.d.ts +1 -1
  118. package/dist/node/handle-event.js +12 -8
  119. package/dist/node/types.d.ts +21 -4
  120. package/dist/node/utilities/fetch.js +1 -1
  121. package/dist/node/utilities/flattenConnection/flattenConnection.d.ts +0 -7
  122. package/dist/node/utilities/flattenConnection/flattenConnection.js +0 -7
  123. package/dist/node/utilities/isClient/isClient.d.ts +0 -4
  124. package/dist/node/utilities/isClient/isClient.js +0 -4
  125. package/dist/node/utilities/isServer/isServer.d.ts +0 -4
  126. package/dist/node/utilities/isServer/isServer.js +1 -5
  127. package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +2 -33
  128. package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.js +0 -31
  129. package/dist/node/utilities/suspense.d.ts +2 -2
  130. package/dist/node/utilities/suspense.js +0 -6
  131. package/dist/node/utilities/video_parameters.js +1 -1
  132. package/dist/node/version.d.ts +1 -1
  133. package/dist/node/version.js +1 -1
  134. package/dist/worker/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
  135. package/dist/worker/framework/Hydration/ServerComponentResponse.server.js +13 -0
  136. package/dist/worker/framework/cache.d.ts +2 -2
  137. package/dist/worker/framework/cache.js +1 -1
  138. package/dist/worker/handle-event.d.ts +1 -1
  139. package/dist/worker/handle-event.js +8 -4
  140. package/dist/worker/types.d.ts +21 -4
  141. package/package.json +11 -9
  142. package/dist/esnext/hooks/useQuery/QueryProvider.d.ts +0 -6
  143. package/dist/esnext/hooks/useQuery/QueryProvider.js +0 -13
  144. package/dist/esnext/hooks/useQuery/hooks.d.ts +0 -15
  145. package/dist/esnext/hooks/useQuery/index.d.ts +0 -2
  146. package/dist/esnext/hooks/useQuery/index.js +0 -2
@@ -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
+ }
@@ -7,12 +7,14 @@ import { useServerState } from '../useServerState';
7
7
  * server state, which in turn fetches the correct server component.
8
8
  */
9
9
  export function ServerStateRouter() {
10
- const { setServerState, pending } = useServerState();
10
+ const { setServerState, pending, serverState } = useServerState();
11
11
  const [isNavigating, setIsNavigating] = useState(false);
12
12
  const location = useLocation();
13
13
  useEffect(() => {
14
- setIsNavigating(true);
15
- setServerState('pathname', location.pathname);
14
+ if (serverState.pathname !== location.pathname) {
15
+ setIsNavigating(true);
16
+ setServerState('pathname', location.pathname);
17
+ }
16
18
  }, [location.pathname, setServerState]);
17
19
  useEffect(() => {
18
20
  /**
@@ -1,17 +1,25 @@
1
1
  import React, { ReactNode } from 'react';
2
+ declare global {
3
+ var __DEV__: boolean;
4
+ }
5
+ export interface ServerState {
6
+ pathname: string;
7
+ search: string;
8
+ [key: string]: any;
9
+ }
10
+ export interface ServerStateSetter {
11
+ (input: ((prev: ServerState) => Partial<ServerState>) | Partial<ServerState> | string, propValue?: any): void;
12
+ }
2
13
  export interface ServerStateContextValue {
3
- serverState: Record<string, any>;
4
- setServerState(input: (() => void) | Record<string, any> | string, value?: string | Record<string, any>): void;
5
- pending: any;
14
+ pending: boolean;
15
+ serverState: ServerState;
16
+ setServerState: ServerStateSetter;
6
17
  }
7
- export declare const ServerStateContext: React.Context<any>;
8
- interface Props {
9
- serverState: Record<string, any>;
10
- setServerState: React.Dispatch<React.SetStateAction<{
11
- pathname: string;
12
- search: string;
13
- }>>;
18
+ export declare const ServerStateContext: React.Context<ServerStateContextValue>;
19
+ interface ServerStateProviderProps {
20
+ serverState: ServerState;
21
+ setServerState: React.Dispatch<React.SetStateAction<ServerState>>;
14
22
  children: ReactNode;
15
23
  }
16
- export declare function ServerStateProvider({ serverState, setServerState, children, }: Props): JSX.Element;
24
+ export declare function ServerStateProvider({ serverState, setServerState, children, }: ServerStateProviderProps): JSX.Element;
17
25
  export {};
@@ -4,7 +4,7 @@ useTransition, } from 'react';
4
4
  export const ServerStateContext = createContext(null);
5
5
  export function ServerStateProvider({ serverState, setServerState, children, }) {
6
6
  const [pending, startTransition] = useTransition();
7
- const setServerStateCallback = useCallback((input, value) => {
7
+ const setServerStateCallback = useCallback((input, propValue) => {
8
8
  /**
9
9
  * By wrapping this state change in a transition, React renders the new state
10
10
  * concurrently in a new "tree" instead of Suspending and showing the (blank)
@@ -13,26 +13,27 @@ export function ServerStateProvider({ serverState, setServerState, children, })
13
13
  * the `pending` flag also provided by the hook to display in the UI.
14
14
  */
15
15
  startTransition(() => {
16
- // Support callback-style setState
17
- if (typeof input === 'function') {
18
- // @ts-ignore
19
- return setServerState(input);
20
- }
21
- // Support a simple object, and spread it into the existing object.
22
- if (typeof input === 'object') {
23
- return setServerState((prev) => ({
16
+ return setServerState((prev) => {
17
+ let newValue;
18
+ if (typeof input === 'function') {
19
+ newValue = input(prev);
20
+ }
21
+ else if (typeof input === 'string') {
22
+ newValue = { [input]: propValue };
23
+ }
24
+ else {
25
+ newValue = input;
26
+ }
27
+ if (__DEV__) {
28
+ if ('request' in newValue || 'response' in newValue) {
29
+ console.warn(`Custom "request" and "response" properties in server state are ignored. Use a different name.`);
30
+ }
31
+ }
32
+ return {
24
33
  ...prev,
25
- // @ts-ignore
26
- ...input,
27
- }));
28
- }
29
- // Support a key, value as well.
30
- if (typeof input === 'string') {
31
- return setServerState((prev) => ({
32
- ...prev,
33
- [input]: value,
34
- }));
35
- }
34
+ ...newValue,
35
+ };
36
+ });
36
37
  });
37
38
  }, [setServerState, startTransition]);
38
39
  const value = useMemo(() => ({
@@ -1 +1,2 @@
1
- export { ServerStateProvider, ServerStateContext, ServerStateContextValue, } from './ServerStateProvider.client';
1
+ export { ServerStateProvider, ServerStateContext, } from './ServerStateProvider.client';
2
+ export type { ServerState, ServerStateContextValue, } from './ServerStateProvider.client';
@@ -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 '../../hooks/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
- }
@@ -0,0 +1,17 @@
1
+ import type { CacheOptions, QueryKey } from '../../types';
2
+ import type { RenderCacheResult } from '../RenderCacheProvider/types';
3
+ export interface HydrogenUseQueryOptions {
4
+ cache: CacheOptions;
5
+ }
6
+ /**
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.
10
+ */
11
+ export declare function useQuery<T>(
12
+ /** A string or array to uniquely identify the current query. */
13
+ key: QueryKey,
14
+ /** An asynchronous query function like `fetch` which returns data. */
15
+ queryFn: () => Promise<T>,
16
+ /** Options including `cache` to manage the cache behavior of the sub-request. */
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,13 +13,19 @@ 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) {
19
+ const resolvedQueryOptions = {
20
+ ...(queryOptions !== null && queryOptions !== void 0 ? queryOptions : {}),
21
+ };
14
22
  /**
15
23
  * Attempt to read the query from cache. If it doesn't exist or if it's stale, regenerate it.
16
24
  */
17
25
  async function cachedQueryFn() {
18
26
  const cacheResponse = await getItemFromCache(key);
19
27
  async function generateNewOutput() {
20
- return await queryFn({});
28
+ return await queryFn();
21
29
  }
22
30
  if (cacheResponse) {
23
31
  const [output, response] = cacheResponse;
@@ -35,7 +43,7 @@ queryOptions) {
35
43
  await setItemInCache(lockKey, true);
36
44
  try {
37
45
  const output = await generateNewOutput();
38
- await setItemInCache(key, output, queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.cache);
46
+ await setItemInCache(key, output, resolvedQueryOptions === null || resolvedQueryOptions === void 0 ? void 0 : resolvedQueryOptions.cache);
39
47
  }
40
48
  catch (e) {
41
49
  console.error(`Error generating async response: ${e.message}`);
@@ -51,8 +59,8 @@ queryOptions) {
51
59
  /**
52
60
  * Important: Do this async
53
61
  */
54
- runDelayedFunction(async () => await setItemInCache(key, newOutput, queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.cache));
62
+ runDelayedFunction(async () => await setItemInCache(key, newOutput, resolvedQueryOptions === null || resolvedQueryOptions === void 0 ? void 0 : resolvedQueryOptions.cache));
55
63
  return newOutput;
56
64
  }
57
- return useReactQuery(key, cachedQueryFn, queryOptions);
65
+ return cachedQueryFn;
58
66
  }
@@ -0,0 +1 @@
1
+ export { useQuery } from './hooks';
@@ -0,0 +1 @@
1
+ export { useQuery } from './hooks';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The `useServerState` hook allows you to [manage server state](/api/hydrogen/framework/server-state) when using Hydrogen as a React Server Component framework.
2
+ * The `useServerState` hook allows you to [manage server state](/custom-storefronts/hydrogen/framework/server-state) when using Hydrogen as a React Server Component framework.
3
3
  *
4
4
  * ## Return value
5
5
  *
@@ -12,4 +12,4 @@
12
12
  * | `pending` | Whether a [transition is pending](https://github.com/reactwg/react-18/discussions/41). |
13
13
  *
14
14
  */
15
- export declare function useServerState(): any;
15
+ export declare function useServerState(): import("../ServerStateProvider").ServerStateContextValue;
@@ -1,7 +1,7 @@
1
1
  import { useContext } from 'react';
2
2
  import { ServerStateContext } from '../ServerStateProvider';
3
3
  /**
4
- * The `useServerState` hook allows you to [manage server state](/api/hydrogen/framework/server-state) when using Hydrogen as a React Server Component framework.
4
+ * The `useServerState` hook allows you to [manage server state](/custom-storefronts/hydrogen/framework/server-state) when using Hydrogen as a React Server Component framework.
5
5
  *
6
6
  * ## Return value
7
7
  *
@@ -12,7 +12,6 @@ export function wrapInClientMarker(meta) {
12
12
  // Use object syntax here to make sure the function name
13
13
  // comes from the meta params for better error stacks.
14
14
  const wrappedComponent = {
15
- // eslint-disable-next-line react/display-name
16
15
  [name]: (props) => React.createElement(ClientMarker, { ...{ props, meta } }),
17
16
  }[name];
18
17
  // Relay component properties such as `Image.Fragment`
@@ -111,7 +111,9 @@ export async function convertHydrationResponseToReactComponents(response) {
111
111
  function createManifestFromWirePayload(payload) {
112
112
  return payload.split('\n').reduce((memo, row) => {
113
113
  const [key, ...values] = row.split(':');
114
- memo[key] = JSON.parse(values.join(':'));
114
+ if (key) {
115
+ memo[key] = JSON.parse(values.join(':'));
116
+ }
115
117
  return memo;
116
118
  }, {});
117
119
  }
@@ -2,6 +2,10 @@ import { CacheOptions } from '../../types';
2
2
  export declare class ServerComponentResponse extends Response {
3
3
  private wait;
4
4
  private cacheOptions?;
5
+ customStatus?: {
6
+ code?: number;
7
+ text?: string;
8
+ };
5
9
  /**
6
10
  * Allow custom body to be a string or a Promise.
7
11
  */
@@ -14,6 +18,12 @@ export declare class ServerComponentResponse extends Response {
14
18
  canStream(): boolean;
15
19
  cache(options: CacheOptions): void;
16
20
  get cacheControlHeader(): string;
21
+ writeHead({ status, statusText, headers, }?: {
22
+ status?: number;
23
+ statusText?: string;
24
+ headers?: Record<string, any>;
25
+ }): void;
26
+ redirect(location: string, status?: number): void;
17
27
  /**
18
28
  * Send the response from a Server Component. Renders React components to string,
19
29
  * and returns `null` to make React happy.
@@ -30,6 +30,19 @@ export class ServerComponentResponse extends Response {
30
30
  };
31
31
  return generateCacheControlHeader(options);
32
32
  }
33
+ writeHead({ status, statusText, headers, } = {}) {
34
+ if (status || statusText) {
35
+ this.customStatus = { code: status, text: statusText };
36
+ }
37
+ if (headers) {
38
+ for (const [key, value] of Object.entries(headers)) {
39
+ this.headers.set(key, value);
40
+ }
41
+ }
42
+ }
43
+ redirect(location, status = 307) {
44
+ this.writeHead({ status, headers: { location } });
45
+ }
33
46
  /**
34
47
  * Send the response from a Server Component. Renders React components to string,
35
48
  * and returns `null` to make React happy.
@@ -68,7 +68,7 @@ export function generateWireSyntaxFromRenderedHtml(html) {
68
68
  .map((component, idx) => {
69
69
  return `M${idx + 1}:${JSON.stringify(component)}`;
70
70
  })
71
- .join('\n') + `\nJ0:${JSON.stringify(wireModel)}`);
71
+ .join('\n') + `\nJ0:${JSON.stringify(wireModel)}`).trim();
72
72
  }
73
73
  function isDomNode(item) {
74
74
  return item !== null && typeof item === 'object' && '_owner' in item;
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-empty-function */
1
2
  /**
2
3
  * HydrationWriter is an implementation of `WritableStream` which
3
4
  * keeps track of chunks emitted from React's `pipeToNodeWritable`.
@@ -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
@@ -10,9 +10,13 @@ declare type HydrogenMiddlewareArgs = {
10
10
  devServer?: ViteDevServer;
11
11
  cache?: Cache;
12
12
  };
13
+ export declare function graphiqlMiddleware({ shopifyConfig, dev, }: {
14
+ shopifyConfig: ShopifyConfig;
15
+ dev: boolean;
16
+ }): (request: IncomingMessage, response: http.ServerResponse, next: NextFunction) => Promise<void>;
13
17
  /**
14
18
  * Provides middleware to Node.js Express-like servers. Used by the Hydrogen
15
19
  * Vite dev server plugin as well as production Node.js implementation.
16
20
  */
17
- export default function hydrogenMiddleware({ dev, shopifyConfig, cache, indexTemplate, getServerEntrypoint, devServer, }: HydrogenMiddlewareArgs): (request: IncomingMessage, response: http.ServerResponse, next: NextFunction) => Promise<void>;
21
+ export declare function hydrogenMiddleware({ dev, cache, indexTemplate, getServerEntrypoint, devServer, }: HydrogenMiddlewareArgs): (request: IncomingMessage, response: http.ServerResponse, next: NextFunction) => Promise<void>;
18
22
  export {};
@@ -1,15 +1,20 @@
1
1
  import { graphiqlHtml } from './graphiql';
2
2
  import handleEvent from '../handle-event';
3
- /**
4
- * Provides middleware to Node.js Express-like servers. Used by the Hydrogen
5
- * Vite dev server plugin as well as production Node.js implementation.
6
- */
7
- export default function hydrogenMiddleware({ dev, shopifyConfig, cache, indexTemplate, getServerEntrypoint, devServer, }) {
3
+ export function graphiqlMiddleware({ shopifyConfig, dev, }) {
8
4
  return async function (request, response, next) {
9
5
  const graphiqlRequest = dev && isGraphiqlRequest(request);
10
6
  if (graphiqlRequest) {
11
7
  return respondWithGraphiql(response, shopifyConfig);
12
8
  }
9
+ next();
10
+ };
11
+ }
12
+ /**
13
+ * Provides middleware to Node.js Express-like servers. Used by the Hydrogen
14
+ * Vite dev server plugin as well as production Node.js implementation.
15
+ */
16
+ export function hydrogenMiddleware({ dev, cache, indexTemplate, getServerEntrypoint, devServer, }) {
17
+ return async function (request, response, next) {
13
18
  const url = new URL('http://' + request.headers.host + request.originalUrl);
14
19
  const isReactHydrationRequest = url.pathname === '/react';
15
20
  /**
@@ -96,9 +101,8 @@ export default function hydrogenMiddleware({ dev, shopifyConfig, cache, indexTem
96
101
  }
97
102
  function shouldInterceptRequest(request, isReactHydrationRequest) {
98
103
  var _a;
99
- return ((/text\/html|application\/hydrogen/.test((_a = request.headers['accept']) !== null && _a !== void 0 ? _a : '') ||
100
- isReactHydrationRequest) &&
101
- request.url !== '/favicon.ico');
104
+ return (/text\/html|application\/hydrogen/.test((_a = request.headers['accept']) !== null && _a !== void 0 ? _a : '') ||
105
+ isReactHydrationRequest);
102
106
  }
103
107
  /**
104
108
  * /graphiql and /___graphql are supported
@@ -0,0 +1 @@
1
+ export declare function resolve(path: string): string;
@@ -0,0 +1,3 @@
1
+ export function resolve(path) {
2
+ return require.resolve(path);
3
+ }
@@ -1,7 +1,7 @@
1
1
  export default () => {
2
2
  return {
3
3
  name: 'vite-plugin-hydrogen-config',
4
- config: () => ({
4
+ config: (_, env) => ({
5
5
  resolve: {
6
6
  alias: {
7
7
  /**
@@ -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'],
@@ -52,6 +63,9 @@ export default () => {
52
63
  'react-router-dom',
53
64
  ],
54
65
  },
66
+ define: {
67
+ __DEV__: env.mode !== 'production',
68
+ },
55
69
  }),
56
70
  };
57
71
  };
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import { promises as fs } from 'fs';
3
- import hydrogenMiddleware from '../middleware';
3
+ import { hydrogenMiddleware, graphiqlMiddleware } from '../middleware';
4
4
  import { InMemoryCache } from '../cache/in-memory';
5
5
  export default (shopifyConfig, pluginOptions) => {
6
6
  return {
@@ -17,7 +17,13 @@ export default (shopifyConfig, pluginOptions) => {
17
17
  const indexHtml = await fs.readFile(resolve('index.html'), 'utf-8');
18
18
  return await server.transformIndexHtml(url, indexHtml);
19
19
  }
20
- server.middlewares.use(hydrogenMiddleware({
20
+ // The default vite middleware rewrites the URL `/graphqil` to `/index.html`
21
+ // By running this middleware first, we avoid that.
22
+ server.middlewares.use(graphiqlMiddleware({
23
+ shopifyConfig,
24
+ dev: true,
25
+ }));
26
+ return () => server.middlewares.use(hydrogenMiddleware({
21
27
  dev: true,
22
28
  shopifyConfig,
23
29
  indexTemplate: getIndexTemplate,
@@ -1,5 +1,7 @@
1
+ import { normalizePath } from 'vite';
1
2
  import path from 'path';
2
3
  import { proxyClientComponent } from '../server-components';
4
+ import { resolve } from './resolver';
3
5
  export default () => {
4
6
  let config;
5
7
  return {
@@ -32,7 +34,7 @@ export default () => {
32
34
  'When using Hydrogen components within Client Components, use the `@shopify/hydrogen/client` entrypoint instead.');
33
35
  }
34
36
  },
35
- load(id, options) {
37
+ async load(id, options) {
36
38
  if (!isSSR(options))
37
39
  return null;
38
40
  // Wrapped components won't match this becase they end in ?no-proxy
@@ -54,35 +56,23 @@ export default () => {
54
56
  */
55
57
  if (id.includes('/Hydration/client-imports')) {
56
58
  // eslint-disable-next-line node/no-missing-require
57
- const hydrogenPath = path.dirname(require.resolve('@shopify/hydrogen'));
59
+ const hydrogenPath = path.dirname(resolve('@shopify/hydrogen'));
58
60
  const importerPath = path.join(hydrogenPath, 'framework', 'Hydration');
59
- const importerToRootPath = path.relative(importerPath, config.root);
61
+ const importerToRootPath = normalizePath(path.relative(importerPath, config.root));
60
62
  const [importerToRootNested] = importerToRootPath.match(/(\.\.\/)+(\.\.)?/) || [];
61
63
  const userPrefix = path.normalize(path.join(importerPath, importerToRootNested.replace(/\/?$/, path.sep)));
62
64
  const userGlob = path.join(importerToRootPath, 'src', '**/*.client.[jt]sx');
63
65
  const libPrefix = hydrogenPath + path.sep;
64
66
  const libGlob = path.join(path.relative(importerPath, hydrogenPath), 'components', '**/*.client.js');
65
67
  return code
66
- .replace('__USER_COMPONENTS_PREFIX__', userPrefix)
67
- .replace('__USER_COMPONENTS_GLOB__', userGlob)
68
- .replace('__LIB_COMPONENTS_PREFIX__', libPrefix)
69
- .replace('__LIB_COMPONENTS_GLOB__', libGlob);
68
+ .replace('__USER_COMPONENTS_PREFIX__', normalizePath(userPrefix))
69
+ .replace('__USER_COMPONENTS_GLOB__', normalizePath(userGlob))
70
+ .replace('__LIB_COMPONENTS_PREFIX__', normalizePath(libPrefix))
71
+ .replace('__LIB_COMPONENTS_GLOB__', normalizePath(libGlob));
70
72
  }
71
73
  },
72
74
  };
73
- // Mitigation for upcoming minor Vite update
74
- // https://github.com/vitejs/vite/pull/5253
75
- // TO-DO: When the vite package is updated with the above Vite PR,
76
- // clean up this function and treat `options` param as objects
77
- // from this point forward
78
- // Timeline: Targetting for Vite 2.7
79
75
  function isSSR(options) {
80
- if (typeof options === 'boolean') {
81
- return options;
82
- }
83
- if (typeof options === 'object') {
84
- return !!options.ssr;
85
- }
86
- return false;
76
+ return !!(options === null || options === void 0 ? void 0 : options.ssr);
87
77
  }
88
78
  };