@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.
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.d.ts +1 -1
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +3 -3
- package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
- package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.js +1 -1
- package/dist/esnext/components/CartLineProvider/context.d.ts +3 -3
- package/dist/esnext/components/CartProvider/CartProvider.client.js +0 -1
- package/dist/esnext/components/ExternalVideo/ExternalVideo.d.ts +1 -1
- package/dist/esnext/components/Image/Image.d.ts +1 -1
- package/dist/esnext/components/LocalizationProvider/index.d.ts +1 -0
- package/dist/esnext/components/LocalizationProvider/index.js +1 -0
- package/dist/esnext/components/MediaFile/MediaFile.d.ts +1 -1
- package/dist/esnext/components/Metafield/Metafield.client.d.ts +1 -1
- package/dist/esnext/components/Metafield/Metafield.client.js +8 -0
- package/dist/esnext/components/Metafield/MetafieldFragment.d.ts +16 -1
- package/dist/esnext/components/Metafield/components/StarRating/StarRating.d.ts +1 -1
- package/dist/esnext/components/Metafield/index.d.ts +2 -2
- package/dist/esnext/components/Model3D/Model3D.client.d.ts +3 -1
- package/dist/esnext/components/Model3D/Model3D.client.js +1 -1
- package/dist/esnext/components/Money/Money.client.d.ts +1 -1
- package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -3
- package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -3
- package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +1 -1
- package/dist/esnext/components/ProductProvider/context.d.ts +2 -2
- package/dist/esnext/components/ProductProvider/types.d.ts +2 -2
- package/dist/esnext/components/SelectedVariantAddToCartButton/SelectedVariantAddToCartButton.client.d.ts +1 -1
- package/dist/esnext/components/SelectedVariantAddToCartButton/SelectedVariantAddToCartButton.client.js +1 -1
- package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +2 -3
- package/dist/esnext/components/UnitPrice/UnitPrice.client.js +1 -2
- package/dist/esnext/components/Video/Video.d.ts +1 -1
- package/dist/esnext/components/index.d.ts +3 -2
- package/dist/esnext/components/index.js +1 -0
- package/dist/esnext/entry-client.js +4 -6
- package/dist/esnext/entry-server.js +49 -32
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.d.ts +2 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheContext.js +4 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.d.ts +2 -0
- package/dist/esnext/foundation/RenderCacheProvider/RenderCacheProvider.js +5 -0
- package/dist/esnext/foundation/RenderCacheProvider/hook.d.ts +11 -0
- package/dist/esnext/foundation/RenderCacheProvider/hook.js +34 -0
- package/dist/esnext/foundation/RenderCacheProvider/index.d.ts +1 -0
- package/dist/esnext/foundation/RenderCacheProvider/index.js +1 -0
- package/dist/esnext/foundation/RenderCacheProvider/types.d.ts +11 -0
- package/dist/esnext/foundation/RenderCacheProvider/types.js +1 -0
- package/dist/esnext/foundation/Router/ServerStateRouter.client.js +5 -3
- package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.client.d.ts +19 -11
- package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.client.js +21 -20
- package/dist/esnext/foundation/ServerStateProvider/index.d.ts +2 -1
- package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.d.ts +1 -3
- package/dist/esnext/foundation/ShopifyProvider/ShopifyServerProvider.server.js +2 -4
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +0 -5
- package/dist/esnext/foundation/useQuery/hooks.d.ts +17 -0
- package/dist/esnext/{hooks → foundation}/useQuery/hooks.js +14 -6
- package/dist/esnext/foundation/useQuery/index.d.ts +1 -0
- package/dist/esnext/foundation/useQuery/index.js +1 -0
- package/dist/esnext/foundation/useServerState/use-server-state.d.ts +2 -2
- package/dist/esnext/foundation/useServerState/use-server-state.js +1 -1
- package/dist/esnext/framework/ClientMarker/ClientMarker.js +0 -1
- package/dist/esnext/framework/Hydration/Cache.client.js +3 -1
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +13 -0
- package/dist/esnext/framework/Hydration/wire.server.js +1 -1
- package/dist/esnext/framework/Hydration/writer.server.js +1 -0
- package/dist/esnext/framework/cache.d.ts +2 -2
- package/dist/esnext/framework/cache.js +1 -1
- package/dist/esnext/framework/middleware.d.ts +5 -1
- package/dist/esnext/framework/middleware.js +12 -8
- package/dist/esnext/framework/plugins/resolver.d.ts +1 -0
- package/dist/esnext/framework/plugins/resolver.js +3 -0
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +15 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +8 -2
- package/dist/esnext/framework/plugins/vite-plugin-react-server-components-shim.js +10 -20
- package/dist/esnext/framework/server-components.js +25 -47
- package/dist/esnext/graphql/graphql-constants.d.ts +74 -37
- package/dist/esnext/graphql/graphql-constants.js +89 -15
- package/dist/esnext/handle-event.d.ts +1 -1
- package/dist/esnext/handle-event.js +8 -4
- package/dist/esnext/hooks/index.d.ts +1 -1
- package/dist/esnext/hooks/index.js +1 -1
- package/dist/esnext/hooks/useCartLine/useCartLine.d.ts +3 -3
- package/dist/esnext/hooks/useMoney/hooks.js +2 -16
- package/dist/esnext/hooks/useParsedMetafields/useParsedMetafields.d.ts +2 -3
- package/dist/esnext/hooks/useProductOptions/types.d.ts +2 -3
- package/dist/esnext/hooks/useShopQuery/hooks.d.ts +4 -2
- package/dist/esnext/hooks/useShopQuery/hooks.js +22 -13
- package/dist/esnext/types.d.ts +21 -4
- package/dist/esnext/utilities/flattenConnection/flattenConnection.d.ts +0 -7
- package/dist/esnext/utilities/flattenConnection/flattenConnection.js +0 -7
- package/dist/esnext/utilities/isClient/isClient.d.ts +0 -4
- package/dist/esnext/utilities/isClient/isClient.js +0 -4
- package/dist/esnext/utilities/isServer/isServer.d.ts +0 -4
- package/dist/esnext/utilities/isServer/isServer.js +0 -4
- package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +2 -33
- package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.js +0 -31
- package/dist/esnext/utilities/suspense.d.ts +2 -2
- package/dist/esnext/utilities/suspense.js +0 -6
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/ClientMarker/ClientMarker.js +2 -3
- package/dist/node/framework/Hydration/Cache.client.js +7 -5
- package/dist/node/framework/Hydration/HydrationContext.server.js +1 -1
- package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
- package/dist/node/framework/Hydration/ServerComponentResponse.server.js +15 -2
- package/dist/node/framework/Hydration/react-utils.js +3 -3
- package/dist/node/framework/Hydration/wire.server.js +2 -2
- package/dist/node/framework/Hydration/writer.server.js +1 -0
- package/dist/node/framework/cache.d.ts +2 -2
- package/dist/node/framework/cache.js +5 -4
- package/dist/node/framework/middleware.d.ts +5 -1
- package/dist/node/framework/middleware.js +17 -11
- package/dist/node/framework/plugin.js +5 -5
- package/dist/node/framework/plugins/resolver.d.ts +1 -0
- package/dist/node/framework/plugins/resolver.js +7 -0
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +15 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +8 -2
- package/dist/node/framework/plugins/vite-plugin-react-server-components-shim.js +11 -21
- package/dist/node/framework/server-components.js +27 -49
- package/dist/node/handle-event.d.ts +1 -1
- package/dist/node/handle-event.js +12 -8
- package/dist/node/types.d.ts +21 -4
- package/dist/node/utilities/fetch.js +1 -1
- package/dist/node/utilities/flattenConnection/flattenConnection.d.ts +0 -7
- package/dist/node/utilities/flattenConnection/flattenConnection.js +0 -7
- package/dist/node/utilities/isClient/isClient.d.ts +0 -4
- package/dist/node/utilities/isClient/isClient.js +0 -4
- package/dist/node/utilities/isServer/isServer.d.ts +0 -4
- package/dist/node/utilities/isServer/isServer.js +1 -5
- package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.d.ts +2 -33
- package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.js +0 -31
- package/dist/node/utilities/suspense.d.ts +2 -2
- package/dist/node/utilities/suspense.js +0 -6
- package/dist/node/utilities/video_parameters.js +1 -1
- package/dist/node/version.d.ts +1 -1
- package/dist/node/version.js +1 -1
- package/dist/worker/framework/Hydration/ServerComponentResponse.server.d.ts +10 -0
- package/dist/worker/framework/Hydration/ServerComponentResponse.server.js +13 -0
- package/dist/worker/framework/cache.d.ts +2 -2
- package/dist/worker/framework/cache.js +1 -1
- package/dist/worker/handle-event.d.ts +1 -1
- package/dist/worker/handle-event.js +8 -4
- package/dist/worker/types.d.ts +21 -4
- package/package.json +11 -9
- package/dist/esnext/hooks/useQuery/QueryProvider.d.ts +0 -6
- package/dist/esnext/hooks/useQuery/QueryProvider.js +0 -13
- package/dist/esnext/hooks/useQuery/hooks.d.ts +0 -15
- package/dist/esnext/hooks/useQuery/index.d.ts +0 -2
- 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
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
-
|
|
15
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
14
|
+
pending: boolean;
|
|
15
|
+
serverState: ServerState;
|
|
16
|
+
setServerState: ServerStateSetter;
|
|
6
17
|
}
|
|
7
|
-
export declare const ServerStateContext: React.Context<
|
|
8
|
-
interface
|
|
9
|
-
serverState:
|
|
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, }:
|
|
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,
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
4
|
-
|
|
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
|
|
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,
|
|
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,
|
|
62
|
+
runDelayedFunction(async () => await setItemInCache(key, newOutput, resolvedQueryOptions === null || resolvedQueryOptions === void 0 ? void 0 : resolvedQueryOptions.cache));
|
|
55
63
|
return newOutput;
|
|
56
64
|
}
|
|
57
|
-
return
|
|
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](/
|
|
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():
|
|
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](/
|
|
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
|
-
|
|
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,5 +1,4 @@
|
|
|
1
|
-
import type { QueryKey } from '
|
|
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
|
|
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 (
|
|
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;
|
|
@@ -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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
};
|