@shopify/hydrogen 1.0.0 → 1.1.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/client.d.ts +4 -4
- package/dist/esnext/client.js +4 -4
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +1 -1
- package/dist/esnext/components/CartProvider/hooks.client.js +8 -1
- package/dist/esnext/components/Image/Image.js +22 -13
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.d.ts +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +3 -2
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +6 -10
- package/dist/esnext/components/ProductOptionsProvider/context.d.ts +1 -1
- package/dist/esnext/components/ProductOptionsProvider/index.d.ts +0 -1
- package/dist/esnext/components/ProductOptionsProvider/index.js +0 -1
- package/dist/esnext/components/index.d.ts +1 -2
- package/dist/esnext/components/index.js +1 -2
- package/dist/esnext/constants.d.ts +4 -0
- package/dist/esnext/constants.js +4 -0
- package/dist/esnext/entry-server.js +10 -9
- package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js +4 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.client.js +2 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server.js +1 -1
- package/dist/esnext/foundation/Analytics/connectors/Shopify/const.d.ts +0 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/const.js +0 -2
- package/dist/esnext/foundation/DevTools/components/Heading.js +1 -1
- package/dist/esnext/foundation/DevTools/components/Panels.js +25 -19
- package/dist/esnext/foundation/DevTools/components/Performance.client.js +0 -1
- package/dist/esnext/foundation/DevTools/components/Settings.client.js +1 -4
- package/dist/esnext/foundation/DevTools/components/Table.js +3 -3
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.d.ts +1 -2
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.js +2 -4
- package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +3 -3
- package/dist/esnext/foundation/ServerPropsProvider/index.d.ts +1 -2
- package/dist/esnext/foundation/ServerPropsProvider/index.js +1 -1
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.js +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +19 -2
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +17 -0
- package/dist/esnext/foundation/fetchSync/ResponseSync.d.ts +14 -0
- package/dist/esnext/foundation/fetchSync/ResponseSync.js +38 -0
- package/dist/esnext/foundation/fetchSync/client/fetchSync.d.ts +2 -2
- package/dist/esnext/foundation/fetchSync/client/fetchSync.js +5 -10
- package/dist/esnext/foundation/fetchSync/server/fetchSync.d.ts +2 -2
- package/dist/esnext/foundation/fetchSync/server/fetchSync.js +9 -12
- package/dist/esnext/framework/graphiql.js +26 -30
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +35 -6
- package/dist/esnext/hooks/index.d.ts +1 -0
- package/dist/esnext/hooks/index.js +1 -0
- package/dist/esnext/hooks/useLocalization/useLocalization.d.ts +3 -2
- package/dist/esnext/hooks/useLocalization/useLocalization.js +2 -7
- package/dist/esnext/hooks/useProductOptions/helpers.js +1 -1
- package/dist/esnext/hooks/useShopQuery/hooks.js +9 -6
- package/dist/esnext/index.d.ts +6 -5
- package/dist/esnext/index.js +6 -5
- package/dist/esnext/platforms/index.d.ts +1 -0
- package/dist/esnext/platforms/index.js +1 -0
- package/dist/esnext/platforms/node.js +2 -8
- package/dist/esnext/platforms/virtual.d.ts +8 -0
- package/dist/esnext/platforms/virtual.js +14 -0
- package/dist/esnext/platforms/worker.js +7 -7
- package/dist/esnext/utilities/image_size.d.ts +1 -0
- package/dist/esnext/utilities/image_size.js +27 -26
- package/dist/esnext/utilities/index.d.ts +1 -1
- package/dist/esnext/utilities/index.js +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/framework/graphiql.js +26 -30
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +35 -6
- package/package.json +7 -2
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +26 -12
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +26 -12
- package/CHANGELOG.md +0 -2198
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -9
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.js +0 -2
- package/dist/esnext/foundation/fetchSync/types.d.ts +0 -5
- package/dist/esnext/foundation/fetchSync/types.js +0 -1
package/dist/esnext/client.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './components';
|
|
2
2
|
export * from './hooks';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
3
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
4
|
+
export { useShop } from './foundation/useShop';
|
|
5
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './foundation/ServerPropsProvider';
|
|
6
|
+
export { useUrl } from './foundation/useUrl';
|
|
7
7
|
export { Head } from './foundation/Head';
|
|
8
8
|
export * from './utilities';
|
|
9
9
|
export { gql } from './utilities/graphql-tag';
|
package/dist/esnext/client.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './components';
|
|
2
2
|
export * from './hooks';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
3
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
4
|
+
export { useShop } from './foundation/useShop';
|
|
5
|
+
export { ServerPropsProvider, ServerPropsContext, } from './foundation/ServerPropsProvider';
|
|
6
|
+
export { useUrl } from './foundation/useUrl';
|
|
7
7
|
export { Head } from './foundation/Head';
|
|
8
8
|
export * from './utilities';
|
|
9
9
|
export { gql } from './utilities/graphql-tag';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useCart } from '../CartProvider';
|
|
3
|
-
import { useProductOptions } from '
|
|
3
|
+
import { useProductOptions } from '../../hooks/useProductOptions';
|
|
4
4
|
import { BaseButton } from '../BaseButton';
|
|
5
5
|
/**
|
|
6
6
|
* The `AddToCartButton` component renders a button that adds an item to the cart when pressed.
|
|
@@ -2,7 +2,8 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import { useShop } from '../../foundation';
|
|
3
3
|
import { flattenConnection } from '../../utilities';
|
|
4
4
|
import { CartCreate, defaultCartFragment } from './cart-queries';
|
|
5
|
-
import { SHOPIFY_STOREFRONT_ID_HEADER, STOREFRONT_API_PUBLIC_TOKEN_HEADER, } from '../../constants';
|
|
5
|
+
import { SHOPIFY_STOREFRONT_ID_HEADER, STOREFRONT_API_PUBLIC_TOKEN_HEADER, SHOPIFY_STOREFRONT_Y_HEADER, SHOPIFY_STOREFRONT_S_HEADER, SHOPIFY_Y, SHOPIFY_S, } from '../../constants';
|
|
6
|
+
import { parse } from 'worktop/cookie';
|
|
6
7
|
export function useCartFetch() {
|
|
7
8
|
const { storeDomain, storefrontApiVersion, storefrontToken, storefrontId } = useShop();
|
|
8
9
|
return React.useCallback(({ query, variables, }) => {
|
|
@@ -15,6 +16,12 @@ export function useCartFetch() {
|
|
|
15
16
|
if (storefrontId) {
|
|
16
17
|
headers[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;
|
|
17
18
|
}
|
|
19
|
+
// Find Shopify cookies
|
|
20
|
+
const cookieData = parse(document.cookie);
|
|
21
|
+
if (cookieData[SHOPIFY_Y] && cookieData[SHOPIFY_S]) {
|
|
22
|
+
headers[SHOPIFY_STOREFRONT_Y_HEADER] = cookieData[SHOPIFY_Y];
|
|
23
|
+
headers[SHOPIFY_STOREFRONT_S_HEADER] = cookieData[SHOPIFY_S];
|
|
24
|
+
}
|
|
18
25
|
return fetch(`https://${storeDomain}/api/${storefrontApiVersion}/graphql.json`, {
|
|
19
26
|
method: 'POST',
|
|
20
27
|
headers,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { getShopifyImageDimensions, shopifyImageLoader, addImageSizeParametersToUrl, } from '../../utilities';
|
|
2
|
+
import { getShopifyImageDimensions, shopifyImageLoader, addImageSizeParametersToUrl, IMG_SRC_SET_SIZES, } from '../../utilities';
|
|
3
3
|
/**
|
|
4
4
|
* The `Image` component renders an image for the Storefront API's
|
|
5
5
|
* [Image object](https://shopify.dev/api/storefront/reference/common-objects/image) by using the `data` prop, or a custom location by using the `src` prop. You can [customize this component](https://shopify.dev/api/hydrogen/components#customizing-hydrogen-components) using passthrough props.
|
|
@@ -34,7 +34,7 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
34
34
|
if (__HYDROGEN_DEV__ && !data.altText && !rest.alt) {
|
|
35
35
|
console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${`Image: ${data.id ?? data.url}`}`);
|
|
36
36
|
}
|
|
37
|
-
const { width:
|
|
37
|
+
const { width: imgElementWidth, height: imgElementHeight } = getShopifyImageDimensions({
|
|
38
38
|
data,
|
|
39
39
|
loaderOptions,
|
|
40
40
|
elementProps: {
|
|
@@ -42,7 +42,7 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
42
42
|
height,
|
|
43
43
|
},
|
|
44
44
|
});
|
|
45
|
-
if (__HYDROGEN_DEV__ && (!
|
|
45
|
+
if (__HYDROGEN_DEV__ && (!imgElementWidth || !imgElementHeight)) {
|
|
46
46
|
console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. ${`Image: ${data.id ?? data.url}`}`);
|
|
47
47
|
}
|
|
48
48
|
let finalSrc = data.url;
|
|
@@ -50,8 +50,8 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
50
50
|
finalSrc = loader({
|
|
51
51
|
...loaderOptions,
|
|
52
52
|
src: data.url,
|
|
53
|
-
width:
|
|
54
|
-
height:
|
|
53
|
+
width: imgElementWidth,
|
|
54
|
+
height: imgElementHeight,
|
|
55
55
|
});
|
|
56
56
|
if (typeof finalSrc !== 'string' || !finalSrc) {
|
|
57
57
|
throw new Error(`<Image/>: 'loader' did not return a valid string. ${`Image: ${data.id ?? data.url}`}`);
|
|
@@ -59,17 +59,20 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
59
59
|
}
|
|
60
60
|
// determining what the intended width of the image is. For example, if the width is specified and lower than the image width, then that is the maximum image width
|
|
61
61
|
// to prevent generating a srcset with widths bigger than needed or to generate images that would distort because of being larger than original
|
|
62
|
-
const maxWidth = width &&
|
|
62
|
+
const maxWidth = width && imgElementWidth && width < imgElementWidth
|
|
63
|
+
? width
|
|
64
|
+
: imgElementWidth;
|
|
63
65
|
const finalSrcset = rest.srcSet ??
|
|
64
66
|
internalImageSrcSet({
|
|
65
67
|
...loaderOptions,
|
|
66
68
|
widths,
|
|
67
69
|
src: data.url,
|
|
68
70
|
width: maxWidth,
|
|
71
|
+
height: imgElementHeight,
|
|
69
72
|
loader,
|
|
70
73
|
});
|
|
71
74
|
/* eslint-disable hydrogen/prefer-image-component */
|
|
72
|
-
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width:
|
|
75
|
+
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width: imgElementWidth ?? undefined, height: imgElementHeight ?? undefined, srcSet: finalSrcset }));
|
|
73
76
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
74
77
|
}
|
|
75
78
|
function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths, loading, ...rest }) {
|
|
@@ -112,23 +115,29 @@ function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths,
|
|
|
112
115
|
height: loaderOptions?.height ?? height, alt: alt ?? '', loading: loading ?? 'lazy', srcSet: finalSrcset }));
|
|
113
116
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
114
117
|
}
|
|
115
|
-
|
|
116
|
-
// reference: https://shopify.dev/api/liquid/filters/html-filters#image_tag
|
|
117
|
-
const IMG_SRC_SET_SIZES = [352, 832, 1200, 1920, 2560];
|
|
118
|
-
function internalImageSrcSet({ src, width, crop, scale, widths, loader, }) {
|
|
118
|
+
function internalImageSrcSet({ src, width, crop, scale, widths, loader, height, }) {
|
|
119
119
|
const hasCustomWidths = widths && Array.isArray(widths);
|
|
120
|
-
if (hasCustomWidths && widths.some((size) => isNaN(size)))
|
|
120
|
+
if (hasCustomWidths && widths.some((size) => isNaN(size))) {
|
|
121
121
|
throw new Error(`<Image/>: the 'widths' must be an array of numbers`);
|
|
122
|
+
}
|
|
123
|
+
let aspectRatio = 1;
|
|
124
|
+
if (width && height) {
|
|
125
|
+
aspectRatio = Number(height) / Number(width);
|
|
126
|
+
}
|
|
122
127
|
let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;
|
|
123
128
|
if (!hasCustomWidths &&
|
|
124
129
|
width &&
|
|
125
|
-
width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1])
|
|
130
|
+
width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]) {
|
|
126
131
|
setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);
|
|
132
|
+
}
|
|
127
133
|
const srcGenerator = loader ? loader : addImageSizeParametersToUrl;
|
|
128
134
|
return setSizes
|
|
129
135
|
.map((size) => `${srcGenerator({
|
|
130
136
|
src,
|
|
131
137
|
width: size,
|
|
138
|
+
// height is not applied if there is no crop
|
|
139
|
+
// if there is crop, then height is applied as a ratio of the original width + height aspect ratio * size
|
|
140
|
+
height: crop ? Number(size) * aspectRatio : undefined,
|
|
132
141
|
crop,
|
|
133
142
|
scale,
|
|
134
143
|
})} ${size}w`)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { LocalizationContextValue } from '
|
|
2
|
+
import type { LocalizationContextValue } from '../../foundation/ShopifyProvider/types';
|
|
3
3
|
export default function LocalizationClientProvider({ localization, children, }: {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
localization: LocalizationContextValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { LocalizationContext
|
|
2
|
+
import { LocalizationContext } from '../../foundation/ShopifyProvider/ShopifyProvider.client';
|
|
3
3
|
export default function LocalizationClientProvider({ localization, children, }) {
|
|
4
4
|
return (React.createElement(LocalizationContext.Provider, { value: localization }, children));
|
|
5
5
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
import { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export interface LocalizationProviderProps {
|
|
3
4
|
/** A `ReactNode` element. */
|
|
4
5
|
children: ReactNode;
|
|
5
6
|
/**
|
|
6
7
|
* Override the `isoCode` to define the active country
|
|
7
8
|
*/
|
|
8
|
-
countryCode?:
|
|
9
|
+
countryCode?: CountryCode;
|
|
9
10
|
/**
|
|
10
11
|
* Override the `languageCode` to define the active language
|
|
11
12
|
*/
|
|
12
|
-
languageCode?:
|
|
13
|
+
languageCode?: LanguageCode;
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* The `LocalizationProvider` component automatically queries the Storefront API's
|
|
@@ -2,6 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import LocalizationClientProvider from './LocalizationClientProvider.client';
|
|
3
3
|
import { useShop } from '../../foundation/useShop';
|
|
4
4
|
import { useServerRequest } from '../../foundation/ServerRequestProvider';
|
|
5
|
+
import { log } from '../../utilities/log';
|
|
6
|
+
import { getLocalizationContextValue } from '../../foundation/ShopifyProvider/ShopifyProvider.server';
|
|
5
7
|
/**
|
|
6
8
|
* The `LocalizationProvider` component automatically queries the Storefront API's
|
|
7
9
|
* [`localization`](https://shopify.dev/api/storefront/reference/common-objects/queryroot) field
|
|
@@ -10,18 +12,12 @@ import { useServerRequest } from '../../foundation/ServerRequestProvider';
|
|
|
10
12
|
* Any descendents of this provider can use the `useLocalization` hook.
|
|
11
13
|
*/
|
|
12
14
|
export function LocalizationProvider(props) {
|
|
15
|
+
if (import.meta.env.DEV) {
|
|
16
|
+
log.warn('<LocalizationProvider> is no longer necessary. Pass localization props directly to `<ShopifyProvider>` instead.');
|
|
17
|
+
}
|
|
13
18
|
const { defaultLanguageCode, defaultCountryCode } = useShop();
|
|
14
|
-
const languageCode = (props.languageCode ?? defaultLanguageCode).toUpperCase();
|
|
15
|
-
const countryCode = (props.countryCode ?? defaultCountryCode).toUpperCase();
|
|
16
19
|
const request = useServerRequest();
|
|
17
|
-
const localization =
|
|
18
|
-
country: {
|
|
19
|
-
isoCode: countryCode,
|
|
20
|
-
},
|
|
21
|
-
language: {
|
|
22
|
-
isoCode: languageCode,
|
|
23
|
-
},
|
|
24
|
-
};
|
|
20
|
+
const localization = getLocalizationContextValue(defaultLanguageCode, defaultCountryCode, props.languageCode, props.countryCode);
|
|
25
21
|
request.ctx.localization = localization;
|
|
26
22
|
return (React.createElement(LocalizationClientProvider, { localization: localization }, props.children));
|
|
27
23
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ProductOptionsHookValue } from '../../hooks';
|
|
1
|
+
import type { ProductOptionsHookValue } from '../../hooks';
|
|
2
2
|
export declare const ProductOptionsContext: import("react").Context<ProductOptionsHookValue | null>;
|
|
@@ -20,9 +20,8 @@ export { CartShopPayButton } from './CartShopPayButton';
|
|
|
20
20
|
export { CartCost } from './CartCost';
|
|
21
21
|
export { CartProvider, useCart, useInstantCheckout } from './CartProvider';
|
|
22
22
|
export type { State, Status, Cart, CartWithActions, CartAction, } from './CartProvider';
|
|
23
|
-
export { ProductOptionsProvider
|
|
23
|
+
export { ProductOptionsProvider } from './ProductOptionsProvider';
|
|
24
24
|
export { ProductPrice } from './ProductPrice';
|
|
25
25
|
export { BuyNowButton } from './BuyNowButton';
|
|
26
26
|
export { ShopPayButton } from './ShopPayButton';
|
|
27
|
-
export { useLocalization } from '../hooks/useLocalization/useLocalization';
|
|
28
27
|
export { Seo } from './Seo';
|
|
@@ -18,9 +18,8 @@ export { CartCheckoutButton } from './CartCheckoutButton';
|
|
|
18
18
|
export { CartShopPayButton } from './CartShopPayButton';
|
|
19
19
|
export { CartCost } from './CartCost';
|
|
20
20
|
export { CartProvider, useCart, useInstantCheckout } from './CartProvider';
|
|
21
|
-
export { ProductOptionsProvider
|
|
21
|
+
export { ProductOptionsProvider } from './ProductOptionsProvider';
|
|
22
22
|
export { ProductPrice } from './ProductPrice';
|
|
23
23
|
export { BuyNowButton } from './BuyNowButton';
|
|
24
24
|
export { ShopPayButton } from './ShopPayButton';
|
|
25
|
-
export { useLocalization } from '../hooks/useLocalization/useLocalization';
|
|
26
25
|
export { Seo } from './Seo';
|
|
@@ -7,3 +7,7 @@ export declare const STOREFRONT_API_PUBLIC_TOKEN_HEADER = "X-Shopify-Storefront-
|
|
|
7
7
|
export declare const STOREFRONT_API_BUYER_IP_HEADER = "Shopify-Storefront-Buyer-IP";
|
|
8
8
|
export declare const SHOPIFY_STOREFRONT_ID_VARIABLE = "SHOPIFY_STOREFRONT_ID";
|
|
9
9
|
export declare const SHOPIFY_STOREFRONT_ID_HEADER = "Shopify-Storefront-Id";
|
|
10
|
+
export declare const SHOPIFY_STOREFRONT_Y_HEADER = "Shopify-Storefront-Y";
|
|
11
|
+
export declare const SHOPIFY_STOREFRONT_S_HEADER = "Shopify-Storefront-S";
|
|
12
|
+
export declare const SHOPIFY_Y = "_shopify_y";
|
|
13
|
+
export declare const SHOPIFY_S = "_shopify_s";
|
package/dist/esnext/constants.js
CHANGED
|
@@ -7,3 +7,7 @@ export const STOREFRONT_API_PUBLIC_TOKEN_HEADER = 'X-Shopify-Storefront-Access-T
|
|
|
7
7
|
export const STOREFRONT_API_BUYER_IP_HEADER = 'Shopify-Storefront-Buyer-IP';
|
|
8
8
|
export const SHOPIFY_STOREFRONT_ID_VARIABLE = 'SHOPIFY_STOREFRONT_ID';
|
|
9
9
|
export const SHOPIFY_STOREFRONT_ID_HEADER = 'Shopify-Storefront-Id';
|
|
10
|
+
export const SHOPIFY_STOREFRONT_Y_HEADER = 'Shopify-Storefront-Y';
|
|
11
|
+
export const SHOPIFY_STOREFRONT_S_HEADER = 'Shopify-Storefront-S';
|
|
12
|
+
export const SHOPIFY_Y = '_shopify_y';
|
|
13
|
+
export const SHOPIFY_S = '_shopify_s';
|
|
@@ -10,7 +10,6 @@ import { ServerPropsProvider } from './foundation/ServerPropsProvider';
|
|
|
10
10
|
import { isBotUA } from './utilities/bot-ua';
|
|
11
11
|
import { getCache, setCache } from './foundation/runtime';
|
|
12
12
|
import { ssrRenderToPipeableStream, ssrRenderToReadableStream, rscRenderToReadableStream, createFromReadableStream, bufferReadableStream, } from './streaming.server';
|
|
13
|
-
import { RSC_PATHNAME } from './constants';
|
|
14
13
|
import { stripScriptsFromTemplate } from './utilities/template';
|
|
15
14
|
import { setLogger } from './utilities/log/log';
|
|
16
15
|
import { Analytics } from './foundation/Analytics/Analytics.server';
|
|
@@ -110,7 +109,7 @@ export const renderHydrogen = (App) => {
|
|
|
110
109
|
async function processRequest(handleRequest, App, url, request, sessionApi, options, response, hydrogenConfig, revalidate = false) {
|
|
111
110
|
const { dev, nonce, indexTemplate, streamableResponse: nodeResponse } = options;
|
|
112
111
|
const log = getLoggerWithContext(request);
|
|
113
|
-
const isRSCRequest =
|
|
112
|
+
const isRSCRequest = request.isRscRequest();
|
|
114
113
|
const apiRoute = !isRSCRequest && getApiRoute(url, hydrogenConfig.routes);
|
|
115
114
|
// The API Route might have a default export, making it also a server component
|
|
116
115
|
// If it does, only render the API route if the request method is GET
|
|
@@ -123,8 +122,11 @@ async function processRequest(handleRequest, App, url, request, sessionApi, opti
|
|
|
123
122
|
: apiResponse;
|
|
124
123
|
}
|
|
125
124
|
const state = isRSCRequest
|
|
126
|
-
? parseJSON(url.searchParams.get('state') || '{}')
|
|
127
|
-
: {
|
|
125
|
+
? parseJSON(decodeURIComponent(url.searchParams.get('state') || '{}'))
|
|
126
|
+
: {
|
|
127
|
+
pathname: decodeURIComponent(url.pathname),
|
|
128
|
+
search: decodeURIComponent(url.search),
|
|
129
|
+
};
|
|
128
130
|
const rsc = runRSC({ App, state, log, request, response });
|
|
129
131
|
if (isRSCRequest) {
|
|
130
132
|
const buffered = await bufferReadableStream(rsc.readable.getReader());
|
|
@@ -552,13 +554,13 @@ function tagOnWrite(response) {
|
|
|
552
554
|
async function cacheResponse(response, request, chunks, revalidate) {
|
|
553
555
|
const cache = getCache();
|
|
554
556
|
/**
|
|
555
|
-
* Only cache on cachable responses where response
|
|
557
|
+
* Only full page cache on cachable responses where response
|
|
556
558
|
*
|
|
557
559
|
* - have content to cache
|
|
558
560
|
* - have status 200
|
|
559
561
|
* - does not have no-store on cache-control header
|
|
560
562
|
* - does not have set-cookie header
|
|
561
|
-
* - is
|
|
563
|
+
* - is a GET request
|
|
562
564
|
* - does not have a session or does not have an active customer access token
|
|
563
565
|
*/
|
|
564
566
|
if (cache &&
|
|
@@ -566,7 +568,7 @@ async function cacheResponse(response, request, chunks, revalidate) {
|
|
|
566
568
|
response.status === 200 &&
|
|
567
569
|
response.cache().mode !== NO_STORE &&
|
|
568
570
|
!response.headers.has('Set-Cookie') &&
|
|
569
|
-
|
|
571
|
+
/get/i.test(request.method) &&
|
|
570
572
|
!sessionHasCustomerAccessToken(request)) {
|
|
571
573
|
if (revalidate) {
|
|
572
574
|
await saveCacheResponse(response, request, chunks);
|
|
@@ -593,10 +595,9 @@ async function saveCacheResponse(response, request, chunks) {
|
|
|
593
595
|
const cache = getCache();
|
|
594
596
|
if (cache && chunks.length > 0) {
|
|
595
597
|
const { headers, status, statusText } = getResponseOptions(response);
|
|
596
|
-
const url = new URL(request.url);
|
|
597
598
|
headers.set('cache-control', response.cacheControlHeader);
|
|
598
599
|
const currentHeader = headers.get('Content-Type');
|
|
599
|
-
if (!currentHeader &&
|
|
600
|
+
if (!currentHeader && !request.isRscRequest()) {
|
|
600
601
|
headers.set('Content-Type', HTML_CONTENT_TYPE);
|
|
601
602
|
}
|
|
602
603
|
await setItemInCache(request.cacheKey(), new Response(chunks.join(''), {
|
package/dist/esnext/foundation/Analytics/connectors/PerformanceMetrics/PerformanceMetrics.client.js
CHANGED
|
@@ -18,7 +18,7 @@ export function PerformanceMetrics() {
|
|
|
18
18
|
const initTime = new Date().getTime();
|
|
19
19
|
ClientAnalytics.publish(ClientAnalytics.eventNames.PERFORMANCE, true, data);
|
|
20
20
|
const pageData = ClientAnalytics.getPageAnalyticsData();
|
|
21
|
-
const shopId = pageData.shopify
|
|
21
|
+
const shopId = pageData.shopify?.shopId;
|
|
22
22
|
fetch('https://monorail-edge.shopifysvc.com/v1/produce', {
|
|
23
23
|
method: 'post',
|
|
24
24
|
headers: {
|
|
@@ -28,7 +28,9 @@ export function PerformanceMetrics() {
|
|
|
28
28
|
schema_id: 'hydrogen_buyer_performance/2.0',
|
|
29
29
|
payload: {
|
|
30
30
|
...data,
|
|
31
|
-
shop_id: shopId
|
|
31
|
+
shop_id: shopId
|
|
32
|
+
? shopId.substring(shopId.lastIndexOf('/') + 1)
|
|
33
|
+
: '',
|
|
32
34
|
},
|
|
33
35
|
metadata: {
|
|
34
36
|
event_created_at_ms: initTime,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { parse, stringify } from 'worktop/cookie';
|
|
3
|
+
import { SHOPIFY_Y, SHOPIFY_S } from '../../../../constants';
|
|
3
4
|
import { ClientAnalytics } from '../../ClientAnalytics';
|
|
4
5
|
import { buildUUID, addDataIf } from './utils';
|
|
5
|
-
import { SHOPIFY_S, SHOPIFY_Y } from './const';
|
|
6
6
|
const longTermLength = 60 * 60 * 24 * 360 * 2; // ~2 year expiry
|
|
7
7
|
const shortTermLength = 60 * 30; // 30 mins
|
|
8
8
|
const myShopifyDomain = 'myshopify.com';
|
|
@@ -52,7 +52,7 @@ function updateCookie(cookieName, value, maxage, cookieDomain) {
|
|
|
52
52
|
const cookieString = stringify(cookieName, value, {
|
|
53
53
|
maxage,
|
|
54
54
|
domain: getCookieDomain(cookieDomain),
|
|
55
|
-
secure:
|
|
55
|
+
secure: import.meta.env.PROD,
|
|
56
56
|
samesite: 'Lax',
|
|
57
57
|
path: '/',
|
|
58
58
|
});
|
|
@@ -4,11 +4,11 @@ import AnalyticsErrorBoundary from '../../../AnalyticsErrorBoundary.client';
|
|
|
4
4
|
import { useServerRequest } from '../../../ServerRequestProvider';
|
|
5
5
|
import { useServerAnalytics } from '../../hook';
|
|
6
6
|
import { useShop } from '../../../useShop';
|
|
7
|
-
import { SHOPIFY_S, SHOPIFY_Y } from './const';
|
|
8
7
|
import { ShopifyAnalyticsClient } from './ShopifyAnalytics.client';
|
|
9
8
|
import { useShopQuery } from '../../../../hooks/useShopQuery';
|
|
10
9
|
import { CacheLong } from '../../../Cache/strategies';
|
|
11
10
|
import { gql } from '../../../../utilities/graphql-tag';
|
|
11
|
+
import { SHOPIFY_Y, SHOPIFY_S } from '../../../../constants';
|
|
12
12
|
export function ShopifyAnalytics({ cookieDomain }) {
|
|
13
13
|
const { storeDomain } = useShop();
|
|
14
14
|
const request = useServerRequest();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export function Heading({ linkText, url, children, }) {
|
|
3
|
-
return (React.createElement("span", { style: { display: 'flex', alignItems: 'baseline', padding: '0 0
|
|
3
|
+
return (React.createElement("span", { style: { display: 'flex', alignItems: 'baseline', padding: '0 0 0em' } },
|
|
4
4
|
React.createElement("span", { style: { paddingRight: '0em', flex: 1, fontWeight: 'bold' } },
|
|
5
5
|
children,
|
|
6
6
|
' '),
|
|
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|
|
2
2
|
import { ClientAnalytics } from '../../Analytics';
|
|
3
3
|
import { Performance } from './Performance.client';
|
|
4
4
|
import { Settings } from './Settings.client';
|
|
5
|
+
const isComponentPanel = (panel) => panel.component !== undefined;
|
|
5
6
|
export function Panels({ settings }) {
|
|
6
7
|
const [selectedPanel, setSelectedPanel] = useState(0);
|
|
7
8
|
const [navigations, setNavigations] = useState([]);
|
|
@@ -22,36 +23,41 @@ export function Panels({ settings }) {
|
|
|
22
23
|
});
|
|
23
24
|
}, [setNavigations, navigations]);
|
|
24
25
|
const panels = getPanels({ settings, performance: { navigations } });
|
|
25
|
-
const panelComponents = panels.map((obj, index) => (React.createElement("div", { key: obj.content, style: { display: selectedPanel === index ? 'block' : 'none' } }, obj.
|
|
26
|
+
const panelComponents = panels.map((obj, index) => isComponentPanel(obj) ? (React.createElement("div", { key: obj.content, style: { display: selectedPanel === index ? 'block' : 'none' } }, obj.component)) : null);
|
|
26
27
|
return (React.createElement("div", { style: { display: 'flex', height: '100%' } },
|
|
27
|
-
React.createElement("div", { style: { borderRight: '1px solid', padding: '1em 0em' } }, panels.map((
|
|
28
|
+
React.createElement("div", { style: { borderRight: '1px solid', padding: '1em 0em' } }, panels.map((panel, index) => {
|
|
28
29
|
const active = selectedPanel === index;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
const style = {
|
|
31
|
+
padding: '0em 1.25em',
|
|
32
|
+
fontWeight: 'bold',
|
|
33
|
+
textDecoration: active ? 'underline' : 'none',
|
|
34
|
+
display: 'flex',
|
|
35
|
+
justifyContent: 'space-between',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
};
|
|
38
|
+
if (isComponentPanel(panel)) {
|
|
39
|
+
return (React.createElement("button", { key: panel.id, type: "button", style: style, onClick: () => setSelectedPanel(index) },
|
|
40
|
+
React.createElement("span", null, panel.content)));
|
|
41
|
+
}
|
|
42
|
+
return (React.createElement("a", { style: style, target: "_blank", rel: "noreferrer", href: panel.url, key: panel.url },
|
|
43
|
+
panel.content,
|
|
44
|
+
React.createElement("span", null, "\u2197")));
|
|
38
45
|
})),
|
|
39
|
-
React.createElement("div", { style: { padding: '
|
|
40
|
-
}
|
|
41
|
-
function Panel({ children }) {
|
|
42
|
-
return React.createElement("div", null, children);
|
|
46
|
+
React.createElement("div", { style: { padding: '1em', width: '100%' } }, panelComponents[selectedPanel ? selectedPanel : 0])));
|
|
43
47
|
}
|
|
44
48
|
function getPanels({ settings, performance }) {
|
|
45
49
|
const panels = {
|
|
46
50
|
settings: {
|
|
47
51
|
content: 'Settings',
|
|
48
|
-
|
|
49
|
-
icon: '🎛',
|
|
52
|
+
component: React.createElement(Settings, { ...settings }),
|
|
50
53
|
},
|
|
51
54
|
performance: {
|
|
52
55
|
content: 'Performance',
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
component: React.createElement(Performance, { ...performance }),
|
|
57
|
+
},
|
|
58
|
+
graphiql: {
|
|
59
|
+
content: 'GraphiQL',
|
|
60
|
+
url: '/___graphql',
|
|
55
61
|
},
|
|
56
62
|
};
|
|
57
63
|
return Object.keys(panels).map((key) => {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Heading } from './Heading';
|
|
3
2
|
import { Table } from './Table';
|
|
4
3
|
const KEY_MAP = {
|
|
5
4
|
locale: 'Locale',
|
|
@@ -14,7 +13,5 @@ export function Settings(props) {
|
|
|
14
13
|
type: typeof value,
|
|
15
14
|
};
|
|
16
15
|
});
|
|
17
|
-
return
|
|
18
|
-
React.createElement(Heading, null, "Config"),
|
|
19
|
-
React.createElement(Table, { items: items })));
|
|
16
|
+
return React.createElement(Table, { items: items });
|
|
20
17
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export function Table({ items }) {
|
|
3
|
-
const itemsMarkup = items.map(({ key, value }) => (React.createElement("div", { key: key, style: { display: 'flex' } },
|
|
4
|
-
React.createElement("span", { style: {
|
|
5
|
-
React.createElement("span", { style: { width: '70%', fontFamily: 'monospace'
|
|
3
|
+
const itemsMarkup = items.map(({ key, value }) => (React.createElement("div", { key: key, style: { display: 'flex', paddingBottom: '1em', flexDirection: 'column' } },
|
|
4
|
+
React.createElement("span", { style: { fontWeight: 'bold' } }, key),
|
|
5
|
+
React.createElement("span", { style: { width: '70%', fontFamily: 'monospace' } }, value))));
|
|
6
6
|
return React.createElement("ul", null, itemsMarkup);
|
|
7
7
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { ShopifyContextValue } from '../ShopifyProvider/types';
|
|
1
|
+
import type { ShopifyContextValue, LocalizationContextValue } from '../ShopifyProvider/types';
|
|
2
2
|
import type { QueryCacheControlHeaders } from '../../utilities/log/log-cache-header';
|
|
3
3
|
import type { QueryTiming } from '../../utilities/log/log-query-timeline';
|
|
4
4
|
import type { ResolvedHydrogenConfig, PreloadOptions, QueryKey, RuntimeContext } from '../../types';
|
|
5
5
|
import { HelmetData as HeadData } from 'react-helmet-async';
|
|
6
6
|
import { SessionSyncApi } from '../session/session';
|
|
7
|
-
import { LocalizationContextValue } from '../../components/LocalizationProvider/LocalizationContext.client';
|
|
8
7
|
export declare type PreloadQueryEntry = {
|
|
9
8
|
key: QueryKey;
|
|
10
9
|
fetcher: (request: HydrogenRequest) => Promise<unknown>;
|
|
@@ -43,9 +43,7 @@ export class HydrogenRequest extends Request {
|
|
|
43
43
|
}
|
|
44
44
|
this.time = getTime();
|
|
45
45
|
this.id = generateId();
|
|
46
|
-
this.normalizedUrl = this.isRscRequest()
|
|
47
|
-
? normalizeUrl(this.url)
|
|
48
|
-
: this.url;
|
|
46
|
+
this.normalizedUrl = decodeURIComponent(this.isRscRequest() ? normalizeUrl(this.url) : this.url);
|
|
49
47
|
this.ctx = {
|
|
50
48
|
cache: new Map(),
|
|
51
49
|
head: new HeadData({}),
|
|
@@ -130,7 +128,7 @@ export class HydrogenRequest extends Request {
|
|
|
130
128
|
}
|
|
131
129
|
async formData() {
|
|
132
130
|
// @ts-ignore
|
|
133
|
-
if (
|
|
131
|
+
if (__HYDROGEN_WORKER__ || super.formData)
|
|
134
132
|
return super.formData();
|
|
135
133
|
const contentType = this.headers.get('Content-Type') || '';
|
|
136
134
|
// If mimeType’s essence is "multipart/form-data", then:
|
|
@@ -13,12 +13,12 @@ export function ServerPropsProvider({ initialServerProps, setServerPropsForRsc,
|
|
|
13
13
|
setServerPropsForRsc((prev) => getNewValue(prev, input, propValue));
|
|
14
14
|
});
|
|
15
15
|
}, [setServerProps, setServerPropsForRsc]);
|
|
16
|
-
const setLocationServerPropsCallback = useCallback((input
|
|
16
|
+
const setLocationServerPropsCallback = useCallback((input) => {
|
|
17
17
|
// Flush the existing user server state when location changes, leaving only the persisted state
|
|
18
18
|
startTransition(() => {
|
|
19
|
-
setServerPropsForRsc(
|
|
19
|
+
setServerPropsForRsc(input);
|
|
20
20
|
setServerProps({});
|
|
21
|
-
setLocationServerProps(
|
|
21
|
+
setLocationServerProps(input);
|
|
22
22
|
});
|
|
23
23
|
}, [setServerProps, setServerPropsForRsc, setLocationServerProps]);
|
|
24
24
|
const getProposedLocationServerPropsCallback = useCallback((input, propValue) => {
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export { ServerPropsProvider, ServerPropsContext } from './ServerPropsProvider';
|
|
2
|
-
export type { ServerProps, ServerPropsContextValue } from './ServerPropsProvider';
|
|
1
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './ServerPropsProvider';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ServerPropsProvider, ServerPropsContext } from './ServerPropsProvider';
|
|
1
|
+
export { ServerPropsProvider, ServerPropsContext, } from './ServerPropsProvider';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { ShopifyContextValue } from './types';
|
|
1
|
+
import type { ShopifyContextValue, LocalizationContextValue } from './types';
|
|
2
2
|
import React, { ReactNode } from 'react';
|
|
3
3
|
export declare const ShopifyContext: React.Context<ShopifyContextValue | null>;
|
|
4
|
-
export declare
|
|
4
|
+
export declare const LocalizationContext: React.Context<LocalizationContextValue | null>;
|
|
5
|
+
export declare function ShopifyProviderClient({ children, shopifyConfig, localization, }: {
|
|
5
6
|
children: ReactNode;
|
|
6
7
|
shopifyConfig: ShopifyContextValue;
|
|
8
|
+
localization: LocalizationContextValue;
|
|
7
9
|
}): JSX.Element;
|