@shopify/hydrogen 0.18.0 → 0.21.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/CHANGELOG.md +200 -0
- package/config.d.ts +1 -0
- package/dist/esnext/components/CartEstimatedCost/CartEstimatedCost.client.d.ts +1 -1
- package/dist/esnext/components/CartLineImage/CartLineImage.client.d.ts +4 -7
- package/dist/esnext/components/CartLineImage/CartLineImage.client.js +1 -2
- package/dist/esnext/components/CartLinePrice/CartLinePrice.client.d.ts +1 -1
- package/dist/esnext/components/CartProvider/CartProvider.client.d.ts +3 -1
- package/dist/esnext/components/CartProvider/CartProvider.client.js +22 -20
- package/dist/esnext/components/CartProvider/cart-queries.d.ts +10 -9
- package/dist/esnext/components/CartProvider/cart-queries.js +58 -743
- package/dist/esnext/components/CartProvider/hooks.client.js +4 -2
- package/dist/esnext/components/CartProvider/types.d.ts +2 -0
- package/dist/esnext/components/Image/Image.d.ts +78 -34
- package/dist/esnext/components/Image/Image.js +54 -51
- package/dist/esnext/components/Image/index.d.ts +1 -0
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +2 -15
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +2 -6
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +10 -4
- package/dist/esnext/components/MediaFile/MediaFile.d.ts +2 -2
- package/dist/esnext/components/MediaFile/MediaFile.js +2 -2
- package/dist/esnext/components/Money/Money.client.d.ts +11 -5
- package/dist/esnext/components/Money/Money.client.js +16 -3
- package/dist/esnext/components/ProductPrice/ProductPrice.client.d.ts +1 -2
- package/dist/esnext/components/ProductPrice/ProductPrice.client.js +1 -2
- package/dist/esnext/components/Video/Video.d.ts +3 -3
- package/dist/esnext/components/Video/Video.js +7 -4
- package/dist/esnext/components/index.d.ts +0 -3
- package/dist/esnext/components/index.js +0 -3
- package/dist/esnext/entry-server.d.ts +13 -1
- package/dist/esnext/entry-server.js +18 -51
- package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +18 -3
- package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.js +2 -0
- package/dist/esnext/foundation/fetchSync/server/fetchSync.d.ts +1 -1
- package/dist/esnext/foundation/fetchSync/server/fetchSync.js +1 -1
- package/dist/esnext/foundation/useQuery/hooks.js +8 -9
- package/dist/esnext/foundation/useSession/useSession.d.ts +1 -1
- package/dist/esnext/foundation/useSession/useSession.js +1 -1
- package/dist/esnext/framework/Hydration/Html.js +3 -1
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.d.ts +1 -1
- package/dist/esnext/framework/Hydration/ServerComponentResponse.server.js +2 -1
- package/dist/esnext/framework/Hydration/rsc.d.ts +0 -3
- package/dist/esnext/framework/Hydration/rsc.js +40 -12
- package/dist/esnext/framework/cache/in-memory.js +0 -6
- package/dist/esnext/framework/cache-sub-request.d.ts +17 -0
- package/dist/esnext/framework/cache-sub-request.js +64 -0
- package/dist/esnext/framework/cache.d.ts +6 -6
- package/dist/esnext/framework/cache.js +36 -33
- package/dist/esnext/framework/plugin.js +5 -30
- package/dist/esnext/framework/plugins/vite-plugin-client-imports.d.ts +2 -0
- package/dist/esnext/framework/plugins/vite-plugin-client-imports.js +25 -0
- package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +73 -3
- package/dist/esnext/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +6 -4
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +2 -3
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
- package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.js +35 -0
- package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.js +6 -3
- package/dist/esnext/hooks/useCountry/useCountry.d.ts +1 -11
- package/dist/esnext/hooks/useCountry/useCountry.js +1 -1
- package/dist/esnext/index.d.ts +4 -0
- package/dist/esnext/index.js +4 -0
- package/dist/esnext/node.d.ts +1 -0
- package/dist/esnext/node.js +1 -0
- package/dist/esnext/storefront-api-types.d.ts +5 -3
- package/dist/esnext/storefront-api-types.js +5 -3
- package/dist/esnext/types.d.ts +4 -3
- package/dist/esnext/utilities/bot-ua.js +4 -0
- package/dist/esnext/utilities/html-encoding.d.ts +2 -0
- package/dist/esnext/utilities/html-encoding.js +16 -0
- package/dist/esnext/utilities/image_size.d.ts +4 -22
- package/dist/esnext/utilities/image_size.js +15 -33
- package/dist/esnext/utilities/index.d.ts +2 -1
- package/dist/esnext/utilities/index.js +2 -1
- package/dist/esnext/utilities/log/log-cache-api-status.js +5 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/dist/node/components/Image/Image.d.ts +84 -0
- package/dist/node/components/Image/Image.js +86 -0
- package/dist/node/components/Image/index.d.ts +2 -0
- package/dist/node/components/Image/index.js +5 -0
- package/dist/node/entry-server.d.ts +13 -1
- package/dist/node/entry-server.js +18 -51
- package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +18 -3
- package/dist/node/framework/Hydration/Html.js +3 -1
- package/dist/node/framework/Hydration/ServerComponentResponse.server.d.ts +1 -1
- package/dist/node/framework/Hydration/ServerComponentResponse.server.js +2 -1
- package/dist/node/framework/Hydration/rsc.d.ts +0 -3
- package/dist/node/framework/Hydration/rsc.js +40 -12
- package/dist/node/framework/cache/in-memory.js +0 -6
- package/dist/node/framework/cache-sub-request.d.ts +17 -0
- package/dist/node/framework/cache-sub-request.js +95 -0
- package/dist/node/framework/cache.d.ts +6 -6
- package/dist/node/framework/cache.js +38 -35
- package/dist/node/framework/plugin.js +5 -53
- package/dist/node/framework/plugins/vite-plugin-client-imports.d.ts +2 -0
- package/dist/node/framework/plugins/vite-plugin-client-imports.js +28 -0
- package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
- package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +76 -3
- package/dist/node/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
- package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +6 -4
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +1 -1
- package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +2 -3
- package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
- package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.js +41 -0
- package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
- package/dist/node/framework/plugins/vite-plugin-ssr-interop.js +6 -3
- package/dist/node/storefront-api-types.d.ts +5 -3
- package/dist/node/storefront-api-types.js +5 -3
- package/dist/node/types.d.ts +4 -3
- package/dist/node/utilities/bot-ua.js +4 -0
- package/dist/node/utilities/html-encoding.d.ts +2 -0
- package/dist/node/utilities/html-encoding.js +21 -0
- package/dist/node/utilities/image_size.d.ts +4 -22
- package/dist/node/utilities/image_size.js +16 -58
- package/dist/node/utilities/index.d.ts +2 -1
- package/dist/node/utilities/index.js +4 -2
- package/dist/node/utilities/log/log-cache-api-status.js +5 -1
- package/dist/node/version.d.ts +1 -1
- package/dist/node/version.js +1 -1
- package/entry-server.d.ts +1 -1
- package/package.json +3 -3
- package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +200 -31
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +2 -0
- package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +200 -31
- package/vendor/react-server-dom-vite/package.json +2 -1
- package/dist/esnext/components/ProductDescription/ProductDescription.client.d.ts +0 -13
- package/dist/esnext/components/ProductDescription/ProductDescription.client.js +0 -16
- package/dist/esnext/components/ProductDescription/index.d.ts +0 -1
- package/dist/esnext/components/ProductDescription/index.js +0 -1
- package/dist/esnext/components/ProductMetafield/ProductMetafield.client.d.ts +0 -21
- package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +0 -42
- package/dist/esnext/components/ProductMetafield/index.d.ts +0 -2
- package/dist/esnext/components/ProductMetafield/index.js +0 -1
- package/dist/esnext/components/ProductTitle/ProductTitle.client.d.ts +0 -13
- package/dist/esnext/components/ProductTitle/ProductTitle.client.js +0 -16
- package/dist/esnext/components/ProductTitle/index.d.ts +0 -1
- package/dist/esnext/components/ProductTitle/index.js +0 -1
- package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +0 -15
- package/dist/esnext/components/UnitPrice/UnitPrice.client.js +0 -22
- package/dist/esnext/components/UnitPrice/index.d.ts +0 -1
- package/dist/esnext/components/UnitPrice/index.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { addImageSizeParametersToUrl,
|
|
1
|
+
export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, } from './image_size';
|
|
2
2
|
export { addParametersToEmbeddedVideoUrl, useEmbeddedVideoUrl, } from './video_parameters';
|
|
3
3
|
export { loadScript } from './load_script';
|
|
4
4
|
export { wrapPromise } from './suspense';
|
|
@@ -9,3 +9,4 @@ export { getMeasurementAsParts, getMeasurementAsString } from './measurement';
|
|
|
9
9
|
export { parseMetafieldValue } from './parseMetafieldValue';
|
|
10
10
|
export { fetchBuilder, graphqlRequestBody, decodeShopifyId } from './fetch';
|
|
11
11
|
export { getTime } from './timing';
|
|
12
|
+
export { htmlEncode, htmlDecode } from './html-encoding';
|
|
@@ -5,5 +5,9 @@ export function logCacheApiStatus(status, url) {
|
|
|
5
5
|
if (!log.options().showCacheApiStatus) {
|
|
6
6
|
return;
|
|
7
7
|
}
|
|
8
|
-
|
|
8
|
+
let queryName;
|
|
9
|
+
if (/shopify\.dev/.test(url)) {
|
|
10
|
+
queryName = findQueryName(url);
|
|
11
|
+
}
|
|
12
|
+
log.debug(gray(`[Cache] ${status === null || status === void 0 ? void 0 : status.padEnd(8)} ${queryName ? `query ${queryName}` : decodeURIComponent(url)}`));
|
|
9
13
|
}
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "0.
|
|
1
|
+
export declare const LIB_VERSION = "0.21.0";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '0.
|
|
1
|
+
export const LIB_VERSION = '0.21.0';
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { Image as ImageType } from '../../storefront-api-types';
|
|
3
|
+
import type { PartialDeep, Simplify, SetRequired } from 'type-fest';
|
|
4
|
+
declare type HtmlImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
|
|
5
|
+
declare type ImageProps<GenericLoaderOpts> = Simplify<ShopifyImageProps | ExternalImageProps<GenericLoaderOpts>>;
|
|
6
|
+
export declare function Image<GenericLoaderOpts>(props: ImageProps<GenericLoaderOpts>): JSX.Element;
|
|
7
|
+
export declare type ShopifyLoaderOptions = {
|
|
8
|
+
crop?: 'top' | 'bottom' | 'left' | 'right' | 'center';
|
|
9
|
+
scale?: 2 | 3;
|
|
10
|
+
width?: HtmlImageProps['width'] | ImageType['width'];
|
|
11
|
+
height?: HtmlImageProps['height'] | ImageType['height'];
|
|
12
|
+
};
|
|
13
|
+
export declare type ShopifyLoaderParams = Simplify<ShopifyLoaderOptions & {
|
|
14
|
+
src: ImageType['url'];
|
|
15
|
+
}>;
|
|
16
|
+
export declare type ShopifyImageProps = Omit<HtmlImageProps, 'src'> & {
|
|
17
|
+
/** An object with fields that correspond to the Storefront API's
|
|
18
|
+
* [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).
|
|
19
|
+
* The `data` prop is required if `src` isn't used, but both props shouldn't be used
|
|
20
|
+
* at the same time. If both `src` and `data` are passed, then `data` takes priority.
|
|
21
|
+
*/
|
|
22
|
+
data: PartialDeep<ImageType>;
|
|
23
|
+
/** A custom function that generates the image URL. Parameters passed in
|
|
24
|
+
* are either `ShopifyLoaderParams` if using the `data` prop, or the
|
|
25
|
+
* `LoaderOptions` object that you pass to `loaderOptions`.
|
|
26
|
+
*/
|
|
27
|
+
loader?: (params: ShopifyLoaderParams) => string;
|
|
28
|
+
/** An object of `loader` function options. For example, if the `loader` function
|
|
29
|
+
* requires a `scale` option, then the value can be a property of the
|
|
30
|
+
* `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
|
|
31
|
+
* is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
|
|
32
|
+
* prop is used, the data shape is whatever you define it to be, and this shape
|
|
33
|
+
* will be passed to `loader`.
|
|
34
|
+
*/
|
|
35
|
+
loaderOptions?: ShopifyLoaderOptions;
|
|
36
|
+
/**
|
|
37
|
+
* 'src' shouldn't be passed when 'data' is used.
|
|
38
|
+
*/
|
|
39
|
+
src?: never;
|
|
40
|
+
};
|
|
41
|
+
declare type LoaderProps<GenericLoaderOpts> = {
|
|
42
|
+
/** A URL string. This string can be an absolute path or a relative path depending
|
|
43
|
+
* on the `loader`. The `src` prop is required if `data` isn't used, but both
|
|
44
|
+
* props shouldn't be used at the same time. If both `src` and `data` are passed,
|
|
45
|
+
* then `data` takes priority.
|
|
46
|
+
*/
|
|
47
|
+
src: HtmlImageProps['src'];
|
|
48
|
+
/** The integer or string value for the width of the image. This is a required prop
|
|
49
|
+
* when `src` is present.
|
|
50
|
+
*/
|
|
51
|
+
width: HtmlImageProps['width'];
|
|
52
|
+
/** The integer or string value for the height of the image. This is a required prop
|
|
53
|
+
* when `src` is present.
|
|
54
|
+
*/
|
|
55
|
+
height: HtmlImageProps['height'];
|
|
56
|
+
/** An object of `loader` function options. For example, if the `loader` function
|
|
57
|
+
* requires a `scale` option, then the value can be a property of the
|
|
58
|
+
* `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
|
|
59
|
+
* is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
|
|
60
|
+
* prop is used, the data shape is whatever you define it to be, and this shape
|
|
61
|
+
* will be passed to `loader`.
|
|
62
|
+
*/
|
|
63
|
+
loaderOptions?: GenericLoaderOpts;
|
|
64
|
+
};
|
|
65
|
+
declare type ExternalImageProps<GenericLoaderOpts> = SetRequired<HtmlImageProps, 'src' | 'width' | 'height'> & {
|
|
66
|
+
/** A custom function that generates the image URL. Parameters passed in
|
|
67
|
+
* are either `ShopifyLoaderParams` if using the `data` prop, or the
|
|
68
|
+
* `LoaderOptions` object that you pass to `loaderOptions`.
|
|
69
|
+
*/
|
|
70
|
+
loader?: (params: LoaderProps<GenericLoaderOpts>) => string;
|
|
71
|
+
/** An object of `loader` function options. For example, if the `loader` function
|
|
72
|
+
* requires a `scale` option, then the value can be a property of the
|
|
73
|
+
* `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
|
|
74
|
+
* is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
|
|
75
|
+
* prop is used, the data shape is whatever you define it to be, and this shape
|
|
76
|
+
* will be passed to `loader`.
|
|
77
|
+
*/
|
|
78
|
+
loaderOptions?: GenericLoaderOpts;
|
|
79
|
+
/**
|
|
80
|
+
* 'data' shouldn't be passed when 'src' is used.
|
|
81
|
+
*/
|
|
82
|
+
data?: never;
|
|
83
|
+
};
|
|
84
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.Image = void 0;
|
|
27
|
+
const React = __importStar(require("react"));
|
|
28
|
+
const utilities_1 = require("../../utilities");
|
|
29
|
+
function Image(props) {
|
|
30
|
+
if (!props.data && !props.src) {
|
|
31
|
+
throw new Error(`<Image/>: requires either a 'data' or 'src' prop.`);
|
|
32
|
+
}
|
|
33
|
+
if (props.data && props.src) {
|
|
34
|
+
console.warn(`<Image/>: using both 'data' and 'src' props is not supported; using the 'data' prop by default`);
|
|
35
|
+
}
|
|
36
|
+
if (props.data) {
|
|
37
|
+
return React.createElement(ShopifyImage, { ...props });
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
return React.createElement(ExternalImage, { ...props });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.Image = Image;
|
|
44
|
+
function ShopifyImage({ data, width, height, loading, loader = utilities_1.shopifyImageLoader, loaderOptions, ...rest }) {
|
|
45
|
+
var _a, _b, _c;
|
|
46
|
+
if (!data.url) {
|
|
47
|
+
throw new Error(`<Image/>: the 'data' prop requires the 'url' property`);
|
|
48
|
+
}
|
|
49
|
+
if (!data.altText && !rest.alt) {
|
|
50
|
+
console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${data.id ? `Image ID: ${data.id}` : ''}`);
|
|
51
|
+
}
|
|
52
|
+
const { width: finalWidth, height: finalHeight } = (0, utilities_1.getShopifyImageDimensions)(data, loaderOptions);
|
|
53
|
+
if (!finalWidth || !finalHeight) {
|
|
54
|
+
console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties`);
|
|
55
|
+
}
|
|
56
|
+
let finalSrc = data.url;
|
|
57
|
+
if (loader) {
|
|
58
|
+
finalSrc = loader({
|
|
59
|
+
...loaderOptions,
|
|
60
|
+
src: data.url,
|
|
61
|
+
width: finalWidth,
|
|
62
|
+
height: finalHeight,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/* eslint-disable hydrogen/prefer-image-component */
|
|
66
|
+
return (React.createElement("img", { id: (_a = data.id) !== null && _a !== void 0 ? _a : '', alt: (_c = (_b = data.altText) !== null && _b !== void 0 ? _b : rest.alt) !== null && _c !== void 0 ? _c : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy', ...rest, src: finalSrc, width: finalWidth !== null && finalWidth !== void 0 ? finalWidth : undefined, height: finalHeight !== null && finalHeight !== void 0 ? finalHeight : undefined }));
|
|
67
|
+
/* eslint-enable hydrogen/prefer-image-component */
|
|
68
|
+
}
|
|
69
|
+
function ExternalImage({ src, width, height, alt, loader, loaderOptions, loading, ...rest }) {
|
|
70
|
+
if (!width || !height) {
|
|
71
|
+
throw new Error(`<Image/>: when 'src' is provided, 'width' and 'height' are required and need to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);
|
|
72
|
+
}
|
|
73
|
+
if (!alt) {
|
|
74
|
+
console.warn(`<Image/>: when 'src' is provided, 'alt' should also be provided`);
|
|
75
|
+
}
|
|
76
|
+
let finalSrc = src;
|
|
77
|
+
if (loader) {
|
|
78
|
+
finalSrc = loader({ src, width, height, ...loaderOptions });
|
|
79
|
+
if (typeof finalSrc !== 'string' || !finalSrc) {
|
|
80
|
+
throw new Error(`<Image/>: 'loader' did not return a valid string`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/* eslint-disable hydrogen/prefer-image-component */
|
|
84
|
+
return (React.createElement("img", { ...rest, src: finalSrc, width: width, height: height, alt: alt !== null && alt !== void 0 ? alt : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy' }));
|
|
85
|
+
/* eslint-enable hydrogen/prefer-image-component */
|
|
86
|
+
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import
|
|
2
|
+
import { Logger } from './utilities/log';
|
|
3
|
+
import type { HydrogenConfig, ImportGlobEagerOutput } from './types';
|
|
4
|
+
import { ServerComponentResponse } from './framework/Hydration/ServerComponentResponse.server';
|
|
5
|
+
import { ServerComponentRequest } from './framework/Hydration/ServerComponentRequest.server';
|
|
3
6
|
import type { ServerResponse, IncomingMessage } from 'http';
|
|
4
7
|
import { RuntimeContext } from './framework/runtime';
|
|
5
8
|
declare global {
|
|
@@ -20,4 +23,13 @@ export interface RequestHandler {
|
|
|
20
23
|
(request: Request | IncomingMessage, options: RequestHandlerOptions): Promise<Response | undefined>;
|
|
21
24
|
}
|
|
22
25
|
export declare const renderHydrogen: (App: any, hydrogenConfig?: HydrogenConfig | undefined) => RequestHandler;
|
|
26
|
+
declare type SharedServerProps = {
|
|
27
|
+
state?: object | null;
|
|
28
|
+
request: ServerComponentRequest;
|
|
29
|
+
response: ServerComponentResponse;
|
|
30
|
+
log: Logger;
|
|
31
|
+
};
|
|
32
|
+
export declare type AppProps = SharedServerProps & {
|
|
33
|
+
routes?: ImportGlobEagerOutput;
|
|
34
|
+
};
|
|
23
35
|
export default renderHydrogen;
|
|
@@ -44,6 +44,7 @@ const Analytics_server_1 = require("./foundation/Analytics/Analytics.server");
|
|
|
44
44
|
const ServerAnalyticsRoute_server_1 = require("./foundation/Analytics/ServerAnalyticsRoute.server");
|
|
45
45
|
const session_1 = require("./foundation/session/session");
|
|
46
46
|
const parse_1 = require("./utilities/parse");
|
|
47
|
+
const utilities_1 = require("./utilities");
|
|
47
48
|
const DOCTYPE = '<!DOCTYPE html>';
|
|
48
49
|
const CONTENT_TYPE = 'Content-Type';
|
|
49
50
|
const HTML_CONTENT_TYPE = 'text/html; charset=UTF-8';
|
|
@@ -89,7 +90,10 @@ const renderHydrogen = (App, hydrogenConfig) => {
|
|
|
89
90
|
: apiResponse;
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
|
-
const isStreamable =
|
|
93
|
+
const isStreamable = (hydrogenConfig.enableStreaming
|
|
94
|
+
? hydrogenConfig.enableStreaming(request)
|
|
95
|
+
: true) &&
|
|
96
|
+
!(0, bot_ua_1.isBotUA)(url, request.headers.get('user-agent')) &&
|
|
93
97
|
(!!streamableResponse || (await (0, streaming_server_1.isStreamingSupported)()));
|
|
94
98
|
let template = typeof indexTemplate === 'function'
|
|
95
99
|
? await indexTemplate(url.toString())
|
|
@@ -169,11 +173,7 @@ async function render(url, { App, request, template, componentResponse, nonce, l
|
|
|
169
173
|
headers.set(CONTENT_TYPE, HTML_CONTENT_TYPE);
|
|
170
174
|
html = (0, Html_1.applyHtmlHead)(html, request.ctx.head, template);
|
|
171
175
|
if (flight) {
|
|
172
|
-
html = html.replace('</body>', () =>
|
|
173
|
-
init: true,
|
|
174
|
-
nonce,
|
|
175
|
-
chunk: flight,
|
|
176
|
-
})}</body>`);
|
|
176
|
+
html = html.replace('</body>', () => flightContainer(flight) + '</body>');
|
|
177
177
|
}
|
|
178
178
|
postRequestTasks('ssr', status, request, componentResponse);
|
|
179
179
|
return new Response(html, {
|
|
@@ -201,12 +201,10 @@ async function stream(url, { App, request, response, componentResponse, template
|
|
|
201
201
|
const rscToScriptTagReadable = new ReadableStream({
|
|
202
202
|
start(controller) {
|
|
203
203
|
log.trace('rsc start chunks');
|
|
204
|
-
let init = true;
|
|
205
204
|
const encoder = new TextEncoder();
|
|
206
205
|
(0, streaming_server_1.bufferReadableStream)(rscReadable.getReader(), (chunk) => {
|
|
207
|
-
const
|
|
208
|
-
controller.enqueue(encoder.encode(
|
|
209
|
-
init = false;
|
|
206
|
+
const metaTag = flightContainer(chunk);
|
|
207
|
+
controller.enqueue(encoder.encode(metaTag));
|
|
210
208
|
}).then(() => {
|
|
211
209
|
log.trace('rsc finish chunks');
|
|
212
210
|
return controller.close();
|
|
@@ -397,34 +395,15 @@ async function hydrate(url, { App, log, request, response, isStreamable, compone
|
|
|
397
395
|
request,
|
|
398
396
|
response: componentResponse,
|
|
399
397
|
});
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
// Note: CFW does not support reader.piteTo nor iterable syntax
|
|
407
|
-
const bufferedBody = await (0, streaming_server_1.bufferReadableStream)(rscReadable.getReader());
|
|
408
|
-
postRequestTasks('rsc', 200, request, componentResponse);
|
|
409
|
-
return new Response(bufferedBody, {
|
|
410
|
-
headers: {
|
|
411
|
-
'cache-control': componentResponse.cacheControlHeader,
|
|
412
|
-
},
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
else if (response) {
|
|
416
|
-
const rscWriter = await Promise.resolve().then(() => __importStar(require(
|
|
417
|
-
// @ts-ignore
|
|
418
|
-
'@shopify/hydrogen/vendor/react-server-dom-vite/writer.node.server')));
|
|
419
|
-
const streamer = rscWriter.renderToPipeableStream(AppRSC);
|
|
420
|
-
response.writeHead(200, 'ok', {
|
|
398
|
+
const rscReadable = (0, streaming_server_1.rscRenderToReadableStream)(AppRSC);
|
|
399
|
+
// Note: CFW does not support reader.piteTo nor iterable syntax
|
|
400
|
+
const bufferedBody = await (0, streaming_server_1.bufferReadableStream)(rscReadable.getReader());
|
|
401
|
+
postRequestTasks('rsc', 200, request, componentResponse);
|
|
402
|
+
return new Response(bufferedBody, {
|
|
403
|
+
headers: {
|
|
421
404
|
'cache-control': componentResponse.cacheControlHeader,
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
stream.on('finish', function () {
|
|
425
|
-
postRequestTasks('rsc', response.statusCode, request, componentResponse);
|
|
426
|
-
});
|
|
427
|
-
}
|
|
405
|
+
},
|
|
406
|
+
});
|
|
428
407
|
}
|
|
429
408
|
function buildAppRSC({ App, log, state, request, response }) {
|
|
430
409
|
const hydrogenServerProps = { request, response, log };
|
|
@@ -555,20 +534,8 @@ async function createNodeWriter() {
|
|
|
555
534
|
const { PassThrough } = await Promise.resolve().then(() => __importStar(require(streamImport)));
|
|
556
535
|
return new PassThrough();
|
|
557
536
|
}
|
|
558
|
-
function flightContainer(
|
|
559
|
-
|
|
560
|
-
if (init) {
|
|
561
|
-
script += 'var __flight=[];';
|
|
562
|
-
}
|
|
563
|
-
if (chunk) {
|
|
564
|
-
const normalizedChunk = chunk
|
|
565
|
-
// 1. Duplicate the escape char (\) for already escaped characters (e.g. \n or \").
|
|
566
|
-
.replace(/\\/g, String.raw `\\`)
|
|
567
|
-
// 2. Escape existing backticks to allow wrapping the whole thing in `...`.
|
|
568
|
-
.replace(/`/g, String.raw `\``);
|
|
569
|
-
script += `__flight.push(\`${normalizedChunk}\`)`;
|
|
570
|
-
}
|
|
571
|
-
return script + '</script>';
|
|
537
|
+
function flightContainer(chunk) {
|
|
538
|
+
return `<meta data-flight="${(0, utilities_1.htmlEncode)(chunk)}" />`;
|
|
572
539
|
}
|
|
573
540
|
function postRequestTasks(type, status, request, componentResponse) {
|
|
574
541
|
(0, log_1.logServerResponse)(type, request, status);
|
|
@@ -35,12 +35,27 @@ function requestCacheRSC() {
|
|
|
35
35
|
return new Map();
|
|
36
36
|
}
|
|
37
37
|
requestCacheRSC.key = Symbol.for('HYDROGEN_REQUEST');
|
|
38
|
+
// Note: use this only during RSC/Flight rendering. The React dispatcher
|
|
39
|
+
// for SSR/Fizz rendering does not implement getCacheForType.
|
|
40
|
+
function getCacheForType(resource) {
|
|
41
|
+
var _a;
|
|
42
|
+
const dispatcher =
|
|
43
|
+
// @ts-ignore
|
|
44
|
+
react_1.default.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
45
|
+
.ReactCurrentDispatcher.current;
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
if (__DEV__ && typeof jest !== 'undefined' && !dispatcher.getCacheForType) {
|
|
48
|
+
// Jest does not have access to the RSC runtime, mock it here:
|
|
49
|
+
// @ts-ignore
|
|
50
|
+
return ((_a = globalThis.__jestRscCache) !== null && _a !== void 0 ? _a : (globalThis.__jestRscCache = resource()));
|
|
51
|
+
}
|
|
52
|
+
return dispatcher.getCacheForType(resource);
|
|
53
|
+
}
|
|
38
54
|
function ServerRequestProvider({ isRSC, request, children, }) {
|
|
39
55
|
if (isRSC) {
|
|
40
56
|
// Save the request object in a React cache that is
|
|
41
57
|
// scoped to this current rendering.
|
|
42
|
-
|
|
43
|
-
const requestCache = react_1.default.unstable_getCacheForType(requestCacheRSC);
|
|
58
|
+
const requestCache = getCacheForType(requestCacheRSC);
|
|
44
59
|
requestCache.set(requestCacheRSC.key, request);
|
|
45
60
|
return children;
|
|
46
61
|
}
|
|
@@ -54,7 +69,7 @@ function useServerRequest() {
|
|
|
54
69
|
try {
|
|
55
70
|
// This cache only works during RSC rendering:
|
|
56
71
|
// @ts-ignore
|
|
57
|
-
const cache =
|
|
72
|
+
const cache = getCacheForType(requestCacheRSC);
|
|
58
73
|
request = cache ? cache.get(requestCacheRSC.key) : null;
|
|
59
74
|
}
|
|
60
75
|
catch (_a) {
|
|
@@ -33,7 +33,9 @@ function Html({ children, template, htmlAttrs, bodyAttrs }) {
|
|
|
33
33
|
if (import.meta.env.DEV) {
|
|
34
34
|
// Fix React Refresh for async scripts.
|
|
35
35
|
// https://github.com/vitejs/vite/issues/6759
|
|
36
|
-
head =
|
|
36
|
+
head =
|
|
37
|
+
'<script></script>' + // Fix for Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=1737882
|
|
38
|
+
head.replace(/>(\s*?import[\s\w]+?['"]\/@react-refresh)/, ' async="">$1');
|
|
37
39
|
}
|
|
38
40
|
return (react_1.default.createElement("html", { ...attrsToProps(getHtmlAttrs(template)), ...htmlAttrs },
|
|
39
41
|
react_1.default.createElement("head", { dangerouslySetInnerHTML: { __html: head } }),
|
|
@@ -12,6 +12,7 @@ class ServerComponentResponse extends Response {
|
|
|
12
12
|
constructor() {
|
|
13
13
|
super(...arguments);
|
|
14
14
|
this.wait = false;
|
|
15
|
+
this.cacheOptions = (0, CachingStrategy_1.CacheSeconds)();
|
|
15
16
|
/**
|
|
16
17
|
* Allow custom body to be a string or a Promise.
|
|
17
18
|
*/
|
|
@@ -31,7 +32,7 @@ class ServerComponentResponse extends Response {
|
|
|
31
32
|
this.cacheOptions = options;
|
|
32
33
|
}
|
|
33
34
|
get cacheControlHeader() {
|
|
34
|
-
return (0, CachingStrategy_1.generateCacheControlHeader)(this.cacheOptions
|
|
35
|
+
return (0, CachingStrategy_1.generateCacheControlHeader)(this.cacheOptions);
|
|
35
36
|
}
|
|
36
37
|
writeHead({ status, statusText, headers, } = {}) {
|
|
37
38
|
if (status || statusText) {
|
|
@@ -3,12 +3,41 @@
|
|
|
3
3
|
// so it is considered ESM instead of CJS?
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.useRefresh = exports.useServerResponse = void 0;
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
const react_1 = require("react");
|
|
8
6
|
const react_server_dom_vite_1 = require("@shopify/hydrogen/vendor/react-server-dom-vite");
|
|
9
7
|
const constants_1 = require("../../constants");
|
|
8
|
+
const utilities_1 = require("../../utilities");
|
|
10
9
|
let rscReader;
|
|
11
|
-
|
|
10
|
+
// Hydrate an SSR response from <meta> tags placed in the DOM.
|
|
11
|
+
const flightChunks = [];
|
|
12
|
+
const FLIGHT_ATTRIBUTE = 'data-flight';
|
|
13
|
+
function addElementToFlightChunks(el) {
|
|
14
|
+
const chunk = el.getAttribute(FLIGHT_ATTRIBUTE);
|
|
15
|
+
if (chunk) {
|
|
16
|
+
flightChunks.push((0, utilities_1.htmlDecode)(chunk));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Get initial payload
|
|
20
|
+
document
|
|
21
|
+
.querySelectorAll('[' + FLIGHT_ATTRIBUTE + ']')
|
|
22
|
+
.forEach(addElementToFlightChunks);
|
|
23
|
+
// Create a mutation observer on the document to detect when new
|
|
24
|
+
// <meta data-flight> tags are added, and add them to the array.
|
|
25
|
+
const observer = new MutationObserver((mutations) => {
|
|
26
|
+
mutations.forEach((mutation) => {
|
|
27
|
+
mutation.addedNodes.forEach((node) => {
|
|
28
|
+
if (node instanceof HTMLElement &&
|
|
29
|
+
node.tagName === 'META' &&
|
|
30
|
+
node.hasAttribute(FLIGHT_ATTRIBUTE)) {
|
|
31
|
+
addElementToFlightChunks(node);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
observer.observe(document.documentElement, {
|
|
37
|
+
childList: true,
|
|
38
|
+
subtree: true,
|
|
39
|
+
});
|
|
40
|
+
if (flightChunks.length > 0) {
|
|
12
41
|
const contentLoaded = new Promise((resolve) => document.addEventListener('DOMContentLoaded', resolve));
|
|
13
42
|
try {
|
|
14
43
|
rscReader = new ReadableStream({
|
|
@@ -18,9 +47,12 @@ if (globalThis.__flight && __flight.length > 0) {
|
|
|
18
47
|
controller.enqueue(encoder.encode(chunk));
|
|
19
48
|
return 0;
|
|
20
49
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
contentLoaded.then(() =>
|
|
50
|
+
flightChunks.forEach(write);
|
|
51
|
+
flightChunks.push = write;
|
|
52
|
+
contentLoaded.then(() => {
|
|
53
|
+
controller.close();
|
|
54
|
+
observer.disconnect();
|
|
55
|
+
});
|
|
24
56
|
},
|
|
25
57
|
});
|
|
26
58
|
}
|
|
@@ -28,9 +60,7 @@ if (globalThis.__flight && __flight.length > 0) {
|
|
|
28
60
|
// Old browser, will try a new hydration request later
|
|
29
61
|
}
|
|
30
62
|
}
|
|
31
|
-
|
|
32
|
-
return new Map();
|
|
33
|
-
}
|
|
63
|
+
const cache = new Map();
|
|
34
64
|
/**
|
|
35
65
|
* Much of this is borrowed from React's demo implementation:
|
|
36
66
|
* @see https://github.com/reactjs/server-components-demo/blob/main/src/Cache.client.js
|
|
@@ -39,7 +69,6 @@ function createResponseCache() {
|
|
|
39
69
|
*/
|
|
40
70
|
function useServerResponse(state) {
|
|
41
71
|
const key = JSON.stringify(state);
|
|
42
|
-
const cache = (0, react_1.unstable_getCacheForType)(createResponseCache);
|
|
43
72
|
let response = cache.get(key);
|
|
44
73
|
if (response) {
|
|
45
74
|
return response;
|
|
@@ -69,7 +98,6 @@ function useServerResponse(state) {
|
|
|
69
98
|
}
|
|
70
99
|
exports.useServerResponse = useServerResponse;
|
|
71
100
|
function useRefresh() {
|
|
72
|
-
|
|
73
|
-
refreshCache();
|
|
101
|
+
cache.clear();
|
|
74
102
|
}
|
|
75
103
|
exports.useRefresh = useRefresh;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.InMemoryCache = void 0;
|
|
4
|
-
const log_1 = require("../../utilities/log");
|
|
5
4
|
/**
|
|
6
5
|
* This is an in-memory implementation of `Cache` that *barely*
|
|
7
6
|
* works and is only meant to be used during development.
|
|
@@ -11,7 +10,6 @@ class InMemoryCache {
|
|
|
11
10
|
this.store = new Map();
|
|
12
11
|
}
|
|
13
12
|
put(request, response) {
|
|
14
|
-
(0, log_1.logCacheApiStatus)('PUT-dev', request.url);
|
|
15
13
|
this.store.set(request.url, {
|
|
16
14
|
value: response,
|
|
17
15
|
date: new Date(),
|
|
@@ -21,7 +19,6 @@ class InMemoryCache {
|
|
|
21
19
|
var _a, _b;
|
|
22
20
|
const match = this.store.get(request.url);
|
|
23
21
|
if (!match) {
|
|
24
|
-
(0, log_1.logCacheApiStatus)('MISS-dev', request.url);
|
|
25
22
|
return;
|
|
26
23
|
}
|
|
27
24
|
const { value, date } = match;
|
|
@@ -31,7 +28,6 @@ class InMemoryCache {
|
|
|
31
28
|
const age = (new Date().valueOf() - date.valueOf()) / 1000;
|
|
32
29
|
const isMiss = age > maxAge + swr;
|
|
33
30
|
if (isMiss) {
|
|
34
|
-
(0, log_1.logCacheApiStatus)('MISS-dev', request.url);
|
|
35
31
|
this.store.delete(request.url);
|
|
36
32
|
return;
|
|
37
33
|
}
|
|
@@ -39,7 +35,6 @@ class InMemoryCache {
|
|
|
39
35
|
const headers = new Headers(value.headers);
|
|
40
36
|
headers.set('cache', isStale ? 'STALE' : 'HIT');
|
|
41
37
|
headers.set('date', date.toUTCString());
|
|
42
|
-
(0, log_1.logCacheApiStatus)(`${headers.get('cache')}-dev`, request.url);
|
|
43
38
|
const response = new Response(value.body, {
|
|
44
39
|
headers,
|
|
45
40
|
});
|
|
@@ -47,7 +42,6 @@ class InMemoryCache {
|
|
|
47
42
|
}
|
|
48
43
|
delete(request) {
|
|
49
44
|
this.store.delete(request.url);
|
|
50
|
-
(0, log_1.logCacheApiStatus)('DELETE-dev', request.url);
|
|
51
45
|
}
|
|
52
46
|
keys(request) {
|
|
53
47
|
const cacheKeys = [];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { QueryKey, CachingStrategy } from '../types';
|
|
2
|
+
export declare function generateSubRequestCacheControlHeader(userCacheOptions?: CachingStrategy): string;
|
|
3
|
+
/**
|
|
4
|
+
* Get an item from the cache. If a match is found, returns a tuple
|
|
5
|
+
* containing the `JSON.parse` version of the response as well
|
|
6
|
+
* as the response itself so it can be checked for staleness.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getItemFromCache(key: QueryKey): Promise<undefined | [any, Response]>;
|
|
9
|
+
/**
|
|
10
|
+
* Put an item into the cache.
|
|
11
|
+
*/
|
|
12
|
+
export declare function setItemInCache(key: QueryKey, value: any, userCacheOptions?: CachingStrategy): Promise<void>;
|
|
13
|
+
export declare function deleteItemFromCache(key: QueryKey): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Manually check the response to see if it's stale.
|
|
16
|
+
*/
|
|
17
|
+
export declare function isStale(key: QueryKey, response: Response): boolean;
|